summaryrefslogtreecommitdiffstats
path: root/content
diff options
context:
space:
mode:
authorpilgrim@chromium.org <pilgrim@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-04-01 16:08:03 +0000
committerpilgrim@chromium.org <pilgrim@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-04-01 16:08:03 +0000
commitdb3678052d68da10743e5c32ea2408f414b4e9aa (patch)
treef097d35458c1ae3dfb058381a853dbdfce23fb94 /content
parentc3e6249b957c48aa639f662a4e15512b5ff6e7d5 (diff)
downloadchromium_src-db3678052d68da10743e5c32ea2408f414b4e9aa.zip
chromium_src-db3678052d68da10743e5c32ea2408f414b4e9aa.tar.gz
chromium_src-db3678052d68da10743e5c32ea2408f414b4e9aa.tar.bz2
Move appcache_interceptor from webkit/ to content/
BUG=338338 TBR=darin@chromium.org Review URL: https://codereview.chromium.org/214883003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@260882 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content')
-rw-r--r--content/browser/appcache/appcache_interceptor.cc128
-rw-r--r--content/browser/appcache/appcache_interceptor.h82
-rw-r--r--content/browser/appcache/appcache_storage_impl_unittest.cc2034
-rw-r--r--content/browser/loader/cross_site_resource_handler.cc4
-rw-r--r--content/browser/loader/resource_dispatcher_host_impl.cc8
-rw-r--r--content/browser/loader/resource_loader.cc4
-rw-r--r--content/content_browser.gypi2
-rw-r--r--content/content_tests.gypi2
8 files changed, 2255 insertions, 9 deletions
diff --git a/content/browser/appcache/appcache_interceptor.cc b/content/browser/appcache/appcache_interceptor.cc
new file mode 100644
index 0000000..3a2c2bd
--- /dev/null
+++ b/content/browser/appcache/appcache_interceptor.cc
@@ -0,0 +1,128 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/appcache/appcache_interceptor.h"
+
+#include "webkit/browser/appcache/appcache_backend_impl.h"
+#include "webkit/browser/appcache/appcache_host.h"
+#include "webkit/browser/appcache/appcache_request_handler.h"
+#include "webkit/browser/appcache/appcache_service.h"
+#include "webkit/browser/appcache/appcache_url_request_job.h"
+#include "webkit/common/appcache/appcache_interfaces.h"
+
+using appcache::AppCacheBackendImpl;
+using appcache::AppCacheHost;
+using appcache::AppCacheRequestHandler;
+using appcache::AppCacheService;
+using appcache::kNoCacheId;
+using appcache::kNoHostId;
+
+namespace content {
+
+// static
+AppCacheInterceptor* AppCacheInterceptor::GetInstance() {
+ return Singleton<AppCacheInterceptor>::get();
+}
+
+void AppCacheInterceptor::SetHandler(
+ net::URLRequest* request, AppCacheRequestHandler* handler) {
+ request->SetUserData(GetInstance(), handler); // request takes ownership
+}
+
+AppCacheRequestHandler* AppCacheInterceptor::GetHandler(
+ net::URLRequest* request) {
+ return reinterpret_cast<AppCacheRequestHandler*>(
+ request->GetUserData(GetInstance()));
+}
+
+void AppCacheInterceptor::SetExtraRequestInfo(
+ net::URLRequest* request, AppCacheService* service, int process_id,
+ int host_id, ResourceType::Type resource_type) {
+ if (!service || (host_id == kNoHostId))
+ return;
+
+ AppCacheBackendImpl* backend = service->GetBackend(process_id);
+ if (!backend)
+ return;
+
+ // TODO(michaeln): An invalid host id is indicative of bad data
+ // from a child process. How should we handle that here?
+ AppCacheHost* host = backend->GetHost(host_id);
+ if (!host)
+ return;
+
+ // Create a handler for this request and associate it with the request.
+ AppCacheRequestHandler* handler =
+ host->CreateRequestHandler(request, resource_type);
+ if (handler)
+ SetHandler(request, handler);
+}
+
+void AppCacheInterceptor::GetExtraResponseInfo(net::URLRequest* request,
+ int64* cache_id,
+ GURL* manifest_url) {
+ DCHECK(*cache_id == kNoCacheId);
+ DCHECK(manifest_url->is_empty());
+ AppCacheRequestHandler* handler = GetHandler(request);
+ if (handler)
+ handler->GetExtraResponseInfo(cache_id, manifest_url);
+}
+
+void AppCacheInterceptor::PrepareForCrossSiteTransfer(
+ net::URLRequest* request,
+ int old_process_id) {
+ AppCacheRequestHandler* handler = GetHandler(request);
+ if (!handler)
+ return;
+ handler->PrepareForCrossSiteTransfer(old_process_id);
+}
+
+void AppCacheInterceptor::CompleteCrossSiteTransfer(
+ net::URLRequest* request,
+ int new_process_id,
+ int new_host_id) {
+ AppCacheRequestHandler* handler = GetHandler(request);
+ if (!handler)
+ return;
+ DCHECK_NE(kNoHostId, new_host_id);
+ handler->CompleteCrossSiteTransfer(new_process_id,
+ new_host_id);
+}
+
+AppCacheInterceptor::AppCacheInterceptor() {
+ net::URLRequest::Deprecated::RegisterRequestInterceptor(this);
+}
+
+AppCacheInterceptor::~AppCacheInterceptor() {
+ net::URLRequest::Deprecated::UnregisterRequestInterceptor(this);
+}
+
+net::URLRequestJob* AppCacheInterceptor::MaybeIntercept(
+ net::URLRequest* request, net::NetworkDelegate* network_delegate) {
+ AppCacheRequestHandler* handler = GetHandler(request);
+ if (!handler)
+ return NULL;
+ return handler->MaybeLoadResource(request, network_delegate);
+}
+
+net::URLRequestJob* AppCacheInterceptor::MaybeInterceptRedirect(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate,
+ const GURL& location) {
+ AppCacheRequestHandler* handler = GetHandler(request);
+ if (!handler)
+ return NULL;
+ return handler->MaybeLoadFallbackForRedirect(
+ request, network_delegate, location);
+}
+
+net::URLRequestJob* AppCacheInterceptor::MaybeInterceptResponse(
+ net::URLRequest* request, net::NetworkDelegate* network_delegate) {
+ AppCacheRequestHandler* handler = GetHandler(request);
+ if (!handler)
+ return NULL;
+ return handler->MaybeLoadFallbackForResponse(request, network_delegate);
+}
+
+} // namespace content
diff --git a/content/browser/appcache/appcache_interceptor.h b/content/browser/appcache/appcache_interceptor.h
new file mode 100644
index 0000000..bb21b2f
--- /dev/null
+++ b/content/browser/appcache/appcache_interceptor.h
@@ -0,0 +1,82 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_APPCACHE_APPCACHE_INTERCEPTOR_H_
+#define CONTENT_BROWSER_APPCACHE_APPCACHE_INTERCEPTOR_H_
+
+#include "base/memory/singleton.h"
+#include "content/common/content_export.h"
+#include "net/url_request/url_request.h"
+#include "url/gurl.h"
+#include "webkit/common/resource_type.h"
+
+namespace appcache {
+class AppCacheRequestHandler;
+class AppCacheService;
+}
+
+namespace content {
+
+// An interceptor to hijack requests and potentially service them out of
+// the appcache.
+class CONTENT_EXPORT AppCacheInterceptor
+ : public net::URLRequest::Interceptor {
+ public:
+ // Registers a singleton instance with the net library.
+ // Should be called early in the IO thread prior to initiating requests.
+ static void EnsureRegistered() {
+ CHECK(GetInstance());
+ }
+
+ // Must be called to make a request eligible for retrieval from an appcache.
+ static void SetExtraRequestInfo(net::URLRequest* request,
+ appcache::AppCacheService* service,
+ int process_id,
+ int host_id,
+ ResourceType::Type resource_type);
+
+ // May be called after response headers are complete to retrieve extra
+ // info about the response.
+ static void GetExtraResponseInfo(net::URLRequest* request,
+ int64* cache_id,
+ GURL* manifest_url);
+
+ // Methods to support cross site navigations.
+ static void PrepareForCrossSiteTransfer(net::URLRequest* request,
+ int old_process_id);
+ static void CompleteCrossSiteTransfer(net::URLRequest* request,
+ int new_process_id,
+ int new_host_id);
+
+ static AppCacheInterceptor* GetInstance();
+
+ protected:
+ // Override from net::URLRequest::Interceptor:
+ virtual net::URLRequestJob* MaybeIntercept(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate) OVERRIDE;
+ virtual net::URLRequestJob* MaybeInterceptResponse(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate) OVERRIDE;
+ virtual net::URLRequestJob* MaybeInterceptRedirect(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate,
+ const GURL& location) OVERRIDE;
+
+ private:
+ friend struct DefaultSingletonTraits<AppCacheInterceptor>;
+
+ AppCacheInterceptor();
+ virtual ~AppCacheInterceptor();
+
+ static void SetHandler(net::URLRequest* request,
+ appcache::AppCacheRequestHandler* handler);
+ static appcache::AppCacheRequestHandler* GetHandler(net::URLRequest* request);
+
+ DISALLOW_COPY_AND_ASSIGN(AppCacheInterceptor);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_APPCACHE_APPCACHE_INTERCEPTOR_H_
diff --git a/content/browser/appcache/appcache_storage_impl_unittest.cc b/content/browser/appcache/appcache_storage_impl_unittest.cc
new file mode 100644
index 0000000..2e682e2
--- /dev/null
+++ b/content/browser/appcache/appcache_storage_impl_unittest.cc
@@ -0,0 +1,2034 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stack>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/callback.h"
+#include "base/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
+#include "content/browser/appcache/appcache_interceptor.h"
+#include "net/base/net_errors.h"
+#include "net/base/request_priority.h"
+#include "net/http/http_response_headers.h"
+#include "net/url_request/url_request_error_job.h"
+#include "net/url_request/url_request_job_factory_impl.h"
+#include "net/url_request/url_request_test_job.h"
+#include "net/url_request/url_request_test_util.h"
+#include "sql/test/test_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webkit/browser/appcache/appcache.h"
+#include "webkit/browser/appcache/appcache_backend_impl.h"
+#include "webkit/browser/appcache/appcache_database.h"
+#include "webkit/browser/appcache/appcache_entry.h"
+#include "webkit/browser/appcache/appcache_group.h"
+#include "webkit/browser/appcache/appcache_host.h"
+#include "webkit/browser/appcache/appcache_request_handler.h"
+#include "webkit/browser/appcache/appcache_service.h"
+#include "webkit/browser/appcache/appcache_storage_impl.h"
+#include "webkit/browser/quota/quota_manager.h"
+
+using appcache::FALLBACK_NAMESPACE;
+using appcache::NETWORK_NAMESPACE;
+using appcache::AppCacheBackendImpl;
+using appcache::AppCacheDatabase;
+using appcache::AppCacheEntry;
+using appcache::AppCacheFrontend;
+using appcache::AppCacheHost;
+using appcache::AppCacheInfo;
+using appcache::AppCacheGroup;
+using appcache::AppCacheService;
+using appcache::AppCacheStorage;
+using appcache::AppCacheStorageImpl;
+using appcache::AppCacheStorageReference;
+using appcache::AppCache;
+using appcache::ErrorDetails;
+using appcache::EventID;
+using appcache::kNoCacheId;
+using appcache::kNoResponseId;
+using appcache::INTERCEPT_NAMESPACE;
+using appcache::LogLevel;
+using appcache::Namespace;
+using appcache::Status;
+
+namespace content {
+
+namespace {
+
+const base::Time kZeroTime;
+const GURL kManifestUrl("http://blah/manifest");
+const GURL kManifestUrl2("http://blah/manifest2");
+const GURL kManifestUrl3("http://blah/manifest3");
+const GURL kEntryUrl("http://blah/entry");
+const GURL kEntryUrl2("http://blah/entry2");
+const GURL kFallbackNamespace("http://blah/fallback_namespace/");
+const GURL kFallbackNamespace2("http://blah/fallback_namespace/longer");
+const GURL kFallbackTestUrl("http://blah/fallback_namespace/longer/test");
+const GURL kOnlineNamespace("http://blah/online_namespace");
+const GURL kOnlineNamespaceWithinFallback(
+ "http://blah/fallback_namespace/online/");
+const GURL kInterceptNamespace("http://blah/intercept_namespace/");
+const GURL kInterceptNamespace2("http://blah/intercept_namespace/longer/");
+const GURL kInterceptTestUrl("http://blah/intercept_namespace/longer/test");
+const GURL kInterceptPatternNamespace("http://blah/intercept_pattern/*/bar");
+const GURL kInterceptPatternTestPositiveUrl(
+ "http://blah/intercept_pattern/foo/bar");
+const GURL kInterceptPatternTestNegativeUrl(
+ "http://blah/intercept_pattern/foo/not_bar");
+const GURL kFallbackPatternNamespace("http://blah/fallback_pattern/*/bar");
+const GURL kFallbackPatternTestPositiveUrl(
+ "http://blah/fallback_pattern/foo/bar");
+const GURL kFallbackPatternTestNegativeUrl(
+ "http://blah/fallback_pattern/foo/not_bar");
+const GURL kOrigin(kManifestUrl.GetOrigin());
+
+const int kManifestEntryIdOffset = 100;
+const int kFallbackEntryIdOffset = 1000;
+
+const GURL kDefaultEntryUrl("http://blah/makecacheandgroup_default_entry");
+const int kDefaultEntrySize = 10;
+const int kDefaultEntryIdOffset = 12345;
+
+const int kMockQuota = 5000;
+
+// The Reinitialize test needs some http accessible resources to run,
+// we mock stuff inprocess for that.
+class MockHttpServer {
+ public:
+ static GURL GetMockUrl(const std::string& path) {
+ return GURL("http://mockhost/" + path);
+ }
+
+ static net::URLRequestJob* CreateJob(
+ net::URLRequest* request, net::NetworkDelegate* network_delegate) {
+ if (request->url().host() != "mockhost")
+ return new net::URLRequestErrorJob(request, network_delegate, -100);
+
+ std::string headers, body;
+ GetMockResponse(request->url().path(), &headers, &body);
+ return new net::URLRequestTestJob(
+ request, network_delegate, headers, body, true);
+ }
+
+ private:
+ static void GetMockResponse(const std::string& path,
+ std::string* headers,
+ std::string* body) {
+ const char manifest_headers[] =
+ "HTTP/1.1 200 OK\0"
+ "Content-type: text/cache-manifest\0"
+ "\0";
+ const char page_headers[] =
+ "HTTP/1.1 200 OK\0"
+ "Content-type: text/html\0"
+ "\0";
+ const char not_found_headers[] =
+ "HTTP/1.1 404 NOT FOUND\0"
+ "\0";
+
+ if (path == "/manifest") {
+ (*headers) = std::string(manifest_headers, arraysize(manifest_headers));
+ (*body) = "CACHE MANIFEST\n";
+ } else if (path == "/empty.html") {
+ (*headers) = std::string(page_headers, arraysize(page_headers));
+ (*body) = "";
+ } else {
+ (*headers) = std::string(not_found_headers,
+ arraysize(not_found_headers));
+ (*body) = "";
+ }
+ }
+};
+
+class MockHttpServerJobFactory
+ : public net::URLRequestJobFactory::ProtocolHandler {
+ public:
+ virtual net::URLRequestJob* MaybeCreateJob(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate) const OVERRIDE {
+ return MockHttpServer::CreateJob(request, network_delegate);
+ }
+};
+
+class IOThread : public base::Thread {
+ public:
+ explicit IOThread(const char* name)
+ : base::Thread(name) {
+ }
+
+ virtual ~IOThread() {
+ Stop();
+ }
+
+ net::URLRequestContext* request_context() {
+ return request_context_.get();
+ }
+
+ virtual void Init() OVERRIDE {
+ scoped_ptr<net::URLRequestJobFactoryImpl> factory(
+ new net::URLRequestJobFactoryImpl());
+ factory->SetProtocolHandler("http", new MockHttpServerJobFactory);
+ job_factory_ = factory.Pass();
+ request_context_.reset(new net::TestURLRequestContext());
+ request_context_->set_job_factory(job_factory_.get());
+ AppCacheInterceptor::EnsureRegistered();
+ }
+
+ virtual void CleanUp() OVERRIDE {
+ request_context_.reset();
+ job_factory_.reset();
+ }
+
+ private:
+ scoped_ptr<net::URLRequestJobFactory> job_factory_;
+ scoped_ptr<net::URLRequestContext> request_context_;
+};
+
+scoped_ptr<IOThread> io_thread;
+scoped_ptr<base::Thread> db_thread;
+
+} // namespace
+
+class AppCacheStorageImplTest : public testing::Test {
+ public:
+ class MockStorageDelegate : public AppCacheStorage::Delegate {
+ public:
+ explicit MockStorageDelegate(AppCacheStorageImplTest* test)
+ : loaded_cache_id_(0), stored_group_success_(false),
+ would_exceed_quota_(false), obsoleted_success_(false),
+ found_cache_id_(kNoCacheId), test_(test) {
+ }
+
+ virtual void OnCacheLoaded(AppCache* cache, int64 cache_id) OVERRIDE {
+ loaded_cache_ = cache;
+ loaded_cache_id_ = cache_id;
+ test_->ScheduleNextTask();
+ }
+
+ virtual void OnGroupLoaded(AppCacheGroup* group,
+ const GURL& manifest_url) OVERRIDE {
+ loaded_group_ = group;
+ loaded_manifest_url_ = manifest_url;
+ loaded_groups_newest_cache_ = group ? group->newest_complete_cache()
+ : NULL;
+ test_->ScheduleNextTask();
+ }
+
+ virtual void OnGroupAndNewestCacheStored(
+ AppCacheGroup* group, AppCache* newest_cache, bool success,
+ bool would_exceed_quota) OVERRIDE {
+ stored_group_ = group;
+ stored_group_success_ = success;
+ would_exceed_quota_ = would_exceed_quota;
+ test_->ScheduleNextTask();
+ }
+
+ virtual void OnGroupMadeObsolete(AppCacheGroup* group,
+ bool success,
+ int response_code) OVERRIDE {
+ obsoleted_group_ = group;
+ obsoleted_success_ = success;
+ test_->ScheduleNextTask();
+ }
+
+ virtual void OnMainResponseFound(const GURL& url,
+ const AppCacheEntry& entry,
+ const GURL& namespace_entry_url,
+ const AppCacheEntry& fallback_entry,
+ int64 cache_id,
+ int64 group_id,
+ const GURL& manifest_url) OVERRIDE {
+ found_url_ = url;
+ found_entry_ = entry;
+ found_namespace_entry_url_ = namespace_entry_url;
+ found_fallback_entry_ = fallback_entry;
+ found_cache_id_ = cache_id;
+ found_group_id_ = group_id;
+ found_manifest_url_ = manifest_url;
+ test_->ScheduleNextTask();
+ }
+
+ scoped_refptr<AppCache> loaded_cache_;
+ int64 loaded_cache_id_;
+ scoped_refptr<AppCacheGroup> loaded_group_;
+ GURL loaded_manifest_url_;
+ scoped_refptr<AppCache> loaded_groups_newest_cache_;
+ scoped_refptr<AppCacheGroup> stored_group_;
+ bool stored_group_success_;
+ bool would_exceed_quota_;
+ scoped_refptr<AppCacheGroup> obsoleted_group_;
+ bool obsoleted_success_;
+ GURL found_url_;
+ AppCacheEntry found_entry_;
+ GURL found_namespace_entry_url_;
+ AppCacheEntry found_fallback_entry_;
+ int64 found_cache_id_;
+ int64 found_group_id_;
+ GURL found_manifest_url_;
+ AppCacheStorageImplTest* test_;
+ };
+
+ class MockQuotaManager : public quota::QuotaManager {
+ public:
+ MockQuotaManager()
+ : QuotaManager(true /* is_incognito */,
+ base::FilePath(),
+ io_thread->message_loop_proxy().get(),
+ db_thread->message_loop_proxy().get(),
+ NULL),
+ async_(false) {}
+
+ virtual void GetUsageAndQuota(
+ const GURL& origin,
+ quota::StorageType type,
+ const GetUsageAndQuotaCallback& callback) OVERRIDE {
+ EXPECT_EQ(quota::kStorageTypeTemporary, type);
+ if (async_) {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&MockQuotaManager::CallCallback,
+ base::Unretained(this),
+ callback));
+ return;
+ }
+ CallCallback(callback);
+ }
+
+ void CallCallback(const GetUsageAndQuotaCallback& callback) {
+ callback.Run(quota::kQuotaStatusOk, 0, kMockQuota);
+ }
+
+ bool async_;
+
+ protected:
+ virtual ~MockQuotaManager() {}
+ };
+
+ class MockQuotaManagerProxy : public quota::QuotaManagerProxy {
+ public:
+ MockQuotaManagerProxy()
+ : QuotaManagerProxy(NULL, NULL),
+ notify_storage_accessed_count_(0),
+ notify_storage_modified_count_(0),
+ last_delta_(0),
+ mock_manager_(new MockQuotaManager) {
+ manager_ = mock_manager_.get();
+ }
+
+ virtual void NotifyStorageAccessed(quota::QuotaClient::ID client_id,
+ const GURL& origin,
+ quota::StorageType type) OVERRIDE {
+ EXPECT_EQ(quota::QuotaClient::kAppcache, client_id);
+ EXPECT_EQ(quota::kStorageTypeTemporary, type);
+ ++notify_storage_accessed_count_;
+ last_origin_ = origin;
+ }
+
+ virtual void NotifyStorageModified(quota::QuotaClient::ID client_id,
+ const GURL& origin,
+ quota::StorageType type,
+ int64 delta) OVERRIDE {
+ EXPECT_EQ(quota::QuotaClient::kAppcache, client_id);
+ EXPECT_EQ(quota::kStorageTypeTemporary, type);
+ ++notify_storage_modified_count_;
+ last_origin_ = origin;
+ last_delta_ = delta;
+ }
+
+ // Not needed for our tests.
+ virtual void RegisterClient(quota::QuotaClient* client) OVERRIDE {}
+ virtual void NotifyOriginInUse(const GURL& origin) OVERRIDE {}
+ virtual void NotifyOriginNoLongerInUse(const GURL& origin) OVERRIDE {}
+ virtual void SetUsageCacheEnabled(quota::QuotaClient::ID client_id,
+ const GURL& origin,
+ quota::StorageType type,
+ bool enabled) OVERRIDE {}
+ virtual void GetUsageAndQuota(
+ base::SequencedTaskRunner* original_task_runner,
+ const GURL& origin,
+ quota::StorageType type,
+ const GetUsageAndQuotaCallback& callback) OVERRIDE {}
+
+ int notify_storage_accessed_count_;
+ int notify_storage_modified_count_;
+ GURL last_origin_;
+ int last_delta_;
+ scoped_refptr<MockQuotaManager> mock_manager_;
+
+ protected:
+ virtual ~MockQuotaManagerProxy() {}
+ };
+
+ template <class Method>
+ void RunMethod(Method method) {
+ (this->*method)();
+ }
+
+ // Helper callback to run a test on our io_thread. The io_thread is spun up
+ // once and reused for all tests.
+ template <class Method>
+ void MethodWrapper(Method method) {
+ SetUpTest();
+
+ // Ensure InitTask execution prior to conducting a test.
+ FlushDbThreadTasks();
+
+ // We also have to wait for InitTask completion call to be performed
+ // on the IO thread prior to running the test. Its guaranteed to be
+ // queued by this time.
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&AppCacheStorageImplTest::RunMethod<Method>,
+ base::Unretained(this),
+ method));
+ }
+
+ static void SetUpTestCase() {
+ // We start both threads as TYPE_IO because we also use the db_thead
+ // for the disk_cache which needs to be of TYPE_IO.
+ base::Thread::Options options(base::MessageLoop::TYPE_IO, 0);
+ io_thread.reset(new IOThread("AppCacheTest.IOThread"));
+ ASSERT_TRUE(io_thread->StartWithOptions(options));
+ db_thread.reset(new base::Thread("AppCacheTest::DBThread"));
+ ASSERT_TRUE(db_thread->StartWithOptions(options));
+ }
+
+ static void TearDownTestCase() {
+ io_thread.reset(NULL);
+ db_thread.reset(NULL);
+ }
+
+ // Test harness --------------------------------------------------
+
+ AppCacheStorageImplTest() {
+ }
+
+ template <class Method>
+ void RunTestOnIOThread(Method method) {
+ test_finished_event_ .reset(new base::WaitableEvent(false, false));
+ io_thread->message_loop()->PostTask(
+ FROM_HERE, base::Bind(&AppCacheStorageImplTest::MethodWrapper<Method>,
+ base::Unretained(this), method));
+ test_finished_event_->Wait();
+ }
+
+ void SetUpTest() {
+ DCHECK(base::MessageLoop::current() == io_thread->message_loop());
+ service_.reset(new AppCacheService(NULL));
+ service_->Initialize(
+ base::FilePath(), db_thread->message_loop_proxy().get(), NULL);
+ mock_quota_manager_proxy_ = new MockQuotaManagerProxy();
+ service_->quota_manager_proxy_ = mock_quota_manager_proxy_;
+ delegate_.reset(new MockStorageDelegate(this));
+ }
+
+ void TearDownTest() {
+ DCHECK(base::MessageLoop::current() == io_thread->message_loop());
+ storage()->CancelDelegateCallbacks(delegate());
+ group_ = NULL;
+ cache_ = NULL;
+ cache2_ = NULL;
+ mock_quota_manager_proxy_ = NULL;
+ delegate_.reset();
+ service_.reset();
+ FlushDbThreadTasks();
+ }
+
+ void TestFinished() {
+ // We unwind the stack prior to finishing up to let stack
+ // based objects get deleted.
+ DCHECK(base::MessageLoop::current() == io_thread->message_loop());
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&AppCacheStorageImplTest::TestFinishedUnwound,
+ base::Unretained(this)));
+ }
+
+ void TestFinishedUnwound() {
+ TearDownTest();
+ test_finished_event_->Signal();
+ }
+
+ void PushNextTask(const base::Closure& task) {
+ task_stack_.push(task);
+ }
+
+ void ScheduleNextTask() {
+ DCHECK(base::MessageLoop::current() == io_thread->message_loop());
+ if (task_stack_.empty()) {
+ return;
+ }
+ base::MessageLoop::current()->PostTask(FROM_HERE, task_stack_.top());
+ task_stack_.pop();
+ }
+
+ static void SignalEvent(base::WaitableEvent* event) {
+ event->Signal();
+ }
+
+ void FlushDbThreadTasks() {
+ // We pump a task thru the db thread to ensure any tasks previously
+ // scheduled on that thread have been performed prior to return.
+ base::WaitableEvent event(false, false);
+ db_thread->message_loop()->PostTask(
+ FROM_HERE, base::Bind(&AppCacheStorageImplTest::SignalEvent, &event));
+ event.Wait();
+ }
+
+ // LoadCache_Miss ----------------------------------------------------
+
+ void LoadCache_Miss() {
+ // Attempt to load a cache that doesn't exist. Should
+ // complete asynchronously.
+ PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_LoadCache_Miss,
+ base::Unretained(this)));
+
+ storage()->LoadCache(111, delegate());
+ EXPECT_NE(111, delegate()->loaded_cache_id_);
+ }
+
+ void Verify_LoadCache_Miss() {
+ EXPECT_EQ(111, delegate()->loaded_cache_id_);
+ EXPECT_FALSE(delegate()->loaded_cache_.get());
+ EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_accessed_count_);
+ EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_modified_count_);
+ TestFinished();
+ }
+
+ // LoadCache_NearHit -------------------------------------------------
+
+ void LoadCache_NearHit() {
+ // Attempt to load a cache that is currently in use
+ // and does not require loading from storage. This
+ // load should complete syncly.
+
+ // Setup some preconditions. Make an 'unstored' cache for
+ // us to load. The ctor should put it in the working set.
+ int64 cache_id = storage()->NewCacheId();
+ scoped_refptr<AppCache> cache(new AppCache(storage(), cache_id));
+
+ // Conduct the test.
+ storage()->LoadCache(cache_id, delegate());
+ EXPECT_EQ(cache_id, delegate()->loaded_cache_id_);
+ EXPECT_EQ(cache.get(), delegate()->loaded_cache_.get());
+ EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_accessed_count_);
+ EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_modified_count_);
+ TestFinished();
+ }
+
+ // CreateGroup --------------------------------------------
+
+ void CreateGroupInEmptyOrigin() {
+ // Attempt to load a group that doesn't exist, one should
+ // be created for us, but not stored.
+
+ // Since the origin has no groups, the storage class will respond
+ // syncly.
+ storage()->LoadOrCreateGroup(kManifestUrl, delegate());
+ Verify_CreateGroup();
+ }
+
+ void CreateGroupInPopulatedOrigin() {
+ // Attempt to load a group that doesn't exist, one should
+ // be created for us, but not stored.
+ PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_CreateGroup,
+ base::Unretained(this)));
+
+ // Since the origin has groups, storage class will have to
+ // consult the database and completion will be async.
+ storage()->usage_map_[kOrigin] = kDefaultEntrySize;
+
+ storage()->LoadOrCreateGroup(kManifestUrl, delegate());
+ EXPECT_FALSE(delegate()->loaded_group_.get());
+ }
+
+ void Verify_CreateGroup() {
+ EXPECT_EQ(kManifestUrl, delegate()->loaded_manifest_url_);
+ EXPECT_TRUE(delegate()->loaded_group_.get());
+ EXPECT_TRUE(delegate()->loaded_group_->HasOneRef());
+ EXPECT_FALSE(delegate()->loaded_group_->newest_complete_cache());
+
+ // Should not have been stored in the database.
+ AppCacheDatabase::GroupRecord record;
+ EXPECT_FALSE(database()->FindGroup(
+ delegate()->loaded_group_->group_id(), &record));
+
+ EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_accessed_count_);
+ EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_modified_count_);
+
+ TestFinished();
+ }
+
+ // LoadGroupAndCache_FarHit --------------------------------------
+
+ void LoadGroupAndCache_FarHit() {
+ // Attempt to load a cache that is not currently in use
+ // and does require loading from disk. This
+ // load should complete asynchronously.
+ PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_LoadCache_Far_Hit,
+ base::Unretained(this)));
+
+ // Setup some preconditions. Create a group and newest cache that
+ // appear to be "stored" and "not currently in use".
+ MakeCacheAndGroup(kManifestUrl, 1, 1, true);
+ group_ = NULL;
+ cache_ = NULL;
+
+ // Conduct the cache load test, completes async
+ storage()->LoadCache(1, delegate());
+ }
+
+ void Verify_LoadCache_Far_Hit() {
+ EXPECT_TRUE(delegate()->loaded_cache_.get());
+ EXPECT_TRUE(delegate()->loaded_cache_->HasOneRef());
+ EXPECT_EQ(1, delegate()->loaded_cache_id_);
+
+ // The group should also have been loaded.
+ EXPECT_TRUE(delegate()->loaded_cache_->owning_group());
+ EXPECT_TRUE(delegate()->loaded_cache_->owning_group()->HasOneRef());
+ EXPECT_EQ(1, delegate()->loaded_cache_->owning_group()->group_id());
+
+ EXPECT_EQ(1, mock_quota_manager_proxy_->notify_storage_accessed_count_);
+ EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_modified_count_);
+
+ // Drop things from the working set.
+ delegate()->loaded_cache_ = NULL;
+ EXPECT_FALSE(delegate()->loaded_group_.get());
+
+ // Conduct the group load test, also complete asynchronously.
+ PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_LoadGroup_Far_Hit,
+ base::Unretained(this)));
+
+ storage()->LoadOrCreateGroup(kManifestUrl, delegate());
+ }
+
+ void Verify_LoadGroup_Far_Hit() {
+ EXPECT_TRUE(delegate()->loaded_group_.get());
+ EXPECT_EQ(kManifestUrl, delegate()->loaded_manifest_url_);
+ EXPECT_TRUE(delegate()->loaded_group_->newest_complete_cache());
+ delegate()->loaded_groups_newest_cache_ = NULL;
+ EXPECT_TRUE(delegate()->loaded_group_->HasOneRef());
+ EXPECT_EQ(2, mock_quota_manager_proxy_->notify_storage_accessed_count_);
+ EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_modified_count_);
+ TestFinished();
+ }
+
+ // StoreNewGroup --------------------------------------
+
+ void StoreNewGroup() {
+ // Store a group and its newest cache. Should complete asynchronously.
+ PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_StoreNewGroup,
+ base::Unretained(this)));
+
+ // Setup some preconditions. Create a group and newest cache that
+ // appear to be "unstored".
+ group_ = new AppCacheGroup(
+ storage(), kManifestUrl, storage()->NewGroupId());
+ cache_ = new AppCache(storage(), storage()->NewCacheId());
+ cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::EXPLICIT, 1,
+ kDefaultEntrySize));
+ // Hold a ref to the cache simulate the UpdateJob holding that ref,
+ // and hold a ref to the group to simulate the CacheHost holding that ref.
+
+ // Have the quota manager retrun asynchronously for this test.
+ mock_quota_manager_proxy_->mock_manager_->async_ = true;
+
+ // Conduct the store test.
+ storage()->StoreGroupAndNewestCache(group_.get(), cache_.get(), delegate());
+ EXPECT_FALSE(delegate()->stored_group_success_);
+ }
+
+ void Verify_StoreNewGroup() {
+ EXPECT_TRUE(delegate()->stored_group_success_);
+ EXPECT_EQ(group_.get(), delegate()->stored_group_.get());
+ EXPECT_EQ(cache_.get(), group_->newest_complete_cache());
+ EXPECT_TRUE(cache_->is_complete());
+
+ // Should have been stored in the database.
+ AppCacheDatabase::GroupRecord group_record;
+ AppCacheDatabase::CacheRecord cache_record;
+ EXPECT_TRUE(database()->FindGroup(group_->group_id(), &group_record));
+ EXPECT_TRUE(database()->FindCache(cache_->cache_id(), &cache_record));
+
+ // Verify quota bookkeeping
+ EXPECT_EQ(kDefaultEntrySize, storage()->usage_map_[kOrigin]);
+ EXPECT_EQ(1, mock_quota_manager_proxy_->notify_storage_modified_count_);
+ EXPECT_EQ(kOrigin, mock_quota_manager_proxy_->last_origin_);
+ EXPECT_EQ(kDefaultEntrySize, mock_quota_manager_proxy_->last_delta_);
+
+ TestFinished();
+ }
+
+ // StoreExistingGroup --------------------------------------
+
+ void StoreExistingGroup() {
+ // Store a group and its newest cache. Should complete asynchronously.
+ PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_StoreExistingGroup,
+ base::Unretained(this)));
+
+ // Setup some preconditions. Create a group and old complete cache
+ // that appear to be "stored"
+ MakeCacheAndGroup(kManifestUrl, 1, 1, true);
+ EXPECT_EQ(kDefaultEntrySize, storage()->usage_map_[kOrigin]);
+
+ // And a newest unstored complete cache.
+ cache2_ = new AppCache(storage(), 2);
+ cache2_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::MASTER, 1,
+ kDefaultEntrySize + 100));
+
+ // Conduct the test.
+ storage()->StoreGroupAndNewestCache(
+ group_.get(), cache2_.get(), delegate());
+ EXPECT_FALSE(delegate()->stored_group_success_);
+ }
+
+ void Verify_StoreExistingGroup() {
+ EXPECT_TRUE(delegate()->stored_group_success_);
+ EXPECT_EQ(group_.get(), delegate()->stored_group_.get());
+ EXPECT_EQ(cache2_.get(), group_->newest_complete_cache());
+ EXPECT_TRUE(cache2_->is_complete());
+
+ // The new cache should have been stored in the database.
+ AppCacheDatabase::GroupRecord group_record;
+ AppCacheDatabase::CacheRecord cache_record;
+ EXPECT_TRUE(database()->FindGroup(1, &group_record));
+ EXPECT_TRUE(database()->FindCache(2, &cache_record));
+
+ // The old cache should have been deleted
+ EXPECT_FALSE(database()->FindCache(1, &cache_record));
+
+ // Verify quota bookkeeping
+ EXPECT_EQ(kDefaultEntrySize + 100, storage()->usage_map_[kOrigin]);
+ EXPECT_EQ(1, mock_quota_manager_proxy_->notify_storage_modified_count_);
+ EXPECT_EQ(kOrigin, mock_quota_manager_proxy_->last_origin_);
+ EXPECT_EQ(100, mock_quota_manager_proxy_->last_delta_);
+
+ TestFinished();
+ }
+
+ // StoreExistingGroupExistingCache -------------------------------
+
+ void StoreExistingGroupExistingCache() {
+ // Store a group with updates to its existing newest complete cache.
+ // Setup some preconditions. Create a group and a complete cache that
+ // appear to be "stored".
+
+ // Setup some preconditions. Create a group and old complete cache
+ // that appear to be "stored"
+ MakeCacheAndGroup(kManifestUrl, 1, 1, true);
+ EXPECT_EQ(kDefaultEntrySize, storage()->usage_map_[kOrigin]);
+
+ // Change the cache.
+ base::Time now = base::Time::Now();
+ cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::MASTER, 1, 100));
+ cache_->set_update_time(now);
+
+ PushNextTask(base::Bind(
+ &AppCacheStorageImplTest::Verify_StoreExistingGroupExistingCache,
+ base::Unretained(this), now));
+
+ // Conduct the test.
+ EXPECT_EQ(cache_, group_->newest_complete_cache());
+ storage()->StoreGroupAndNewestCache(group_.get(), cache_.get(), delegate());
+ EXPECT_FALSE(delegate()->stored_group_success_);
+ }
+
+ void Verify_StoreExistingGroupExistingCache(
+ base::Time expected_update_time) {
+ EXPECT_TRUE(delegate()->stored_group_success_);
+ EXPECT_EQ(cache_, group_->newest_complete_cache());
+
+ AppCacheDatabase::CacheRecord cache_record;
+ EXPECT_TRUE(database()->FindCache(1, &cache_record));
+ EXPECT_EQ(1, cache_record.cache_id);
+ EXPECT_EQ(1, cache_record.group_id);
+ EXPECT_FALSE(cache_record.online_wildcard);
+ EXPECT_TRUE(expected_update_time == cache_record.update_time);
+ EXPECT_EQ(100 + kDefaultEntrySize, cache_record.cache_size);
+
+ std::vector<AppCacheDatabase::EntryRecord> entry_records;
+ EXPECT_TRUE(database()->FindEntriesForCache(1, &entry_records));
+ EXPECT_EQ(2U, entry_records.size());
+ if (entry_records[0].url == kDefaultEntryUrl)
+ entry_records.erase(entry_records.begin());
+ EXPECT_EQ(1 , entry_records[0].cache_id);
+ EXPECT_EQ(kEntryUrl, entry_records[0].url);
+ EXPECT_EQ(AppCacheEntry::MASTER, entry_records[0].flags);
+ EXPECT_EQ(1, entry_records[0].response_id);
+ EXPECT_EQ(100, entry_records[0].response_size);
+
+ // Verify quota bookkeeping
+ EXPECT_EQ(100 + kDefaultEntrySize, storage()->usage_map_[kOrigin]);
+ EXPECT_EQ(1, mock_quota_manager_proxy_->notify_storage_modified_count_);
+ EXPECT_EQ(kOrigin, mock_quota_manager_proxy_->last_origin_);
+ EXPECT_EQ(100, mock_quota_manager_proxy_->last_delta_);
+
+ TestFinished();
+ }
+
+ // FailStoreGroup --------------------------------------
+
+ void FailStoreGroup() {
+ // Store a group and its newest cache. Should complete asynchronously.
+ PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_FailStoreGroup,
+ base::Unretained(this)));
+
+ // Setup some preconditions. Create a group and newest cache that
+ // appear to be "unstored" and big enough to exceed the 5M limit.
+ const int64 kTooBig = 10 * 1024 * 1024; // 10M
+ group_ = new AppCacheGroup(
+ storage(), kManifestUrl, storage()->NewGroupId());
+ cache_ = new AppCache(storage(), storage()->NewCacheId());
+ cache_->AddEntry(kManifestUrl,
+ AppCacheEntry(AppCacheEntry::MANIFEST, 1, kTooBig));
+ // Hold a ref to the cache simulate the UpdateJob holding that ref,
+ // and hold a ref to the group to simulate the CacheHost holding that ref.
+
+ // Conduct the store test.
+ storage()->StoreGroupAndNewestCache(group_.get(), cache_.get(), delegate());
+ EXPECT_FALSE(delegate()->stored_group_success_); // Expected to be async.
+ }
+
+ void Verify_FailStoreGroup() {
+ EXPECT_FALSE(delegate()->stored_group_success_);
+ EXPECT_TRUE(delegate()->would_exceed_quota_);
+
+ // Should not have been stored in the database.
+ AppCacheDatabase::GroupRecord group_record;
+ AppCacheDatabase::CacheRecord cache_record;
+ EXPECT_FALSE(database()->FindGroup(group_->group_id(), &group_record));
+ EXPECT_FALSE(database()->FindCache(cache_->cache_id(), &cache_record));
+
+ EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_accessed_count_);
+ EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_modified_count_);
+
+ TestFinished();
+ }
+
+ // MakeGroupObsolete -------------------------------
+
+ void MakeGroupObsolete() {
+ // Make a group obsolete, should complete asynchronously.
+ PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_MakeGroupObsolete,
+ base::Unretained(this)));
+
+ // Setup some preconditions. Create a group and newest cache that
+ // appears to be "stored" and "currently in use".
+ MakeCacheAndGroup(kManifestUrl, 1, 1, true);
+ EXPECT_EQ(kDefaultEntrySize, storage()->usage_map_[kOrigin]);
+
+ // Also insert some related records.
+ AppCacheDatabase::EntryRecord entry_record;
+ entry_record.cache_id = 1;
+ entry_record.flags = AppCacheEntry::FALLBACK;
+ entry_record.response_id = 1;
+ entry_record.url = kEntryUrl;
+ EXPECT_TRUE(database()->InsertEntry(&entry_record));
+
+ AppCacheDatabase::NamespaceRecord fallback_namespace_record;
+ fallback_namespace_record.cache_id = 1;
+ fallback_namespace_record.namespace_.target_url = kEntryUrl;
+ fallback_namespace_record.namespace_.namespace_url = kFallbackNamespace;
+ fallback_namespace_record.origin = kManifestUrl.GetOrigin();
+ EXPECT_TRUE(database()->InsertNamespace(&fallback_namespace_record));
+
+ AppCacheDatabase::OnlineWhiteListRecord online_whitelist_record;
+ online_whitelist_record.cache_id = 1;
+ online_whitelist_record.namespace_url = kOnlineNamespace;
+ EXPECT_TRUE(database()->InsertOnlineWhiteList(&online_whitelist_record));
+
+ // Conduct the test.
+ storage()->MakeGroupObsolete(group_.get(), delegate(), 0);
+ EXPECT_FALSE(group_->is_obsolete());
+ }
+
+ void Verify_MakeGroupObsolete() {
+ EXPECT_TRUE(delegate()->obsoleted_success_);
+ EXPECT_EQ(group_.get(), delegate()->obsoleted_group_.get());
+ EXPECT_TRUE(group_->is_obsolete());
+ EXPECT_TRUE(storage()->usage_map_.empty());
+
+ // The cache and group have been deleted from the database.
+ AppCacheDatabase::GroupRecord group_record;
+ AppCacheDatabase::CacheRecord cache_record;
+ EXPECT_FALSE(database()->FindGroup(1, &group_record));
+ EXPECT_FALSE(database()->FindCache(1, &cache_record));
+
+ // The related records should have been deleted too.
+ std::vector<AppCacheDatabase::EntryRecord> entry_records;
+ database()->FindEntriesForCache(1, &entry_records);
+ EXPECT_TRUE(entry_records.empty());
+ std::vector<AppCacheDatabase::NamespaceRecord> intercept_records;
+ std::vector<AppCacheDatabase::NamespaceRecord> fallback_records;
+ database()->FindNamespacesForCache(
+ 1, &intercept_records, &fallback_records);
+ EXPECT_TRUE(fallback_records.empty());
+ std::vector<AppCacheDatabase::OnlineWhiteListRecord> whitelist_records;
+ database()->FindOnlineWhiteListForCache(1, &whitelist_records);
+ EXPECT_TRUE(whitelist_records.empty());
+
+ // Verify quota bookkeeping
+ EXPECT_TRUE(storage()->usage_map_.empty());
+ EXPECT_EQ(1, mock_quota_manager_proxy_->notify_storage_modified_count_);
+ EXPECT_EQ(kOrigin, mock_quota_manager_proxy_->last_origin_);
+ EXPECT_EQ(-kDefaultEntrySize, mock_quota_manager_proxy_->last_delta_);
+
+ TestFinished();
+ }
+
+ // MarkEntryAsForeign -------------------------------
+
+ void MarkEntryAsForeign() {
+ // Setup some preconditions. Create a cache with an entry
+ // in storage and in the working set.
+ MakeCacheAndGroup(kManifestUrl, 1, 1, true);
+ cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::EXPLICIT));
+ AppCacheDatabase::EntryRecord entry_record;
+ entry_record.cache_id = 1;
+ entry_record.url = kEntryUrl;
+ entry_record.flags = AppCacheEntry::EXPLICIT;
+ entry_record.response_id = 0;
+ EXPECT_TRUE(database()->InsertEntry(&entry_record));
+ EXPECT_FALSE(cache_->GetEntry(kEntryUrl)->IsForeign());
+
+ // Conduct the test.
+ storage()->MarkEntryAsForeign(kEntryUrl, 1);
+
+ // The entry in the working set should have been updated syncly.
+ EXPECT_TRUE(cache_->GetEntry(kEntryUrl)->IsForeign());
+ EXPECT_TRUE(cache_->GetEntry(kEntryUrl)->IsExplicit());
+
+ // And the entry in storage should also be updated, but that
+ // happens asynchronously on the db thread.
+ FlushDbThreadTasks();
+ AppCacheDatabase::EntryRecord entry_record2;
+ EXPECT_TRUE(database()->FindEntry(1, kEntryUrl, &entry_record2));
+ EXPECT_EQ(AppCacheEntry::EXPLICIT | AppCacheEntry::FOREIGN,
+ entry_record2.flags);
+ TestFinished();
+ }
+
+ // MarkEntryAsForeignWithLoadInProgress -------------------------------
+
+ void MarkEntryAsForeignWithLoadInProgress() {
+ PushNextTask(base::Bind(
+ &AppCacheStorageImplTest::Verify_MarkEntryAsForeignWithLoadInProgress,
+ base::Unretained(this)));
+
+ // Setup some preconditions. Create a cache with an entry
+ // in storage, but not in the working set.
+ MakeCacheAndGroup(kManifestUrl, 1, 1, true);
+ cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::EXPLICIT));
+ AppCacheDatabase::EntryRecord entry_record;
+ entry_record.cache_id = 1;
+ entry_record.url = kEntryUrl;
+ entry_record.flags = AppCacheEntry::EXPLICIT;
+ entry_record.response_id = 0;
+ EXPECT_TRUE(database()->InsertEntry(&entry_record));
+ EXPECT_FALSE(cache_->GetEntry(kEntryUrl)->IsForeign());
+ EXPECT_TRUE(cache_->HasOneRef());
+ cache_ = NULL;
+ group_ = NULL;
+
+ // Conduct the test, start a cache load, and prior to completion
+ // of that load, mark the entry as foreign.
+ storage()->LoadCache(1, delegate());
+ storage()->MarkEntryAsForeign(kEntryUrl, 1);
+ }
+
+ void Verify_MarkEntryAsForeignWithLoadInProgress() {
+ EXPECT_EQ(1, delegate()->loaded_cache_id_);
+ EXPECT_TRUE(delegate()->loaded_cache_.get());
+
+ // The entry in the working set should have been updated upon load.
+ EXPECT_TRUE(delegate()->loaded_cache_->GetEntry(kEntryUrl)->IsForeign());
+ EXPECT_TRUE(delegate()->loaded_cache_->GetEntry(kEntryUrl)->IsExplicit());
+
+ // And the entry in storage should also be updated.
+ FlushDbThreadTasks();
+ AppCacheDatabase::EntryRecord entry_record;
+ EXPECT_TRUE(database()->FindEntry(1, kEntryUrl, &entry_record));
+ EXPECT_EQ(AppCacheEntry::EXPLICIT | AppCacheEntry::FOREIGN,
+ entry_record.flags);
+ TestFinished();
+ }
+
+ // FindNoMainResponse -------------------------------
+
+ void FindNoMainResponse() {
+ PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_FindNoMainResponse,
+ base::Unretained(this)));
+
+ // Conduct the test.
+ storage()->FindResponseForMainRequest(kEntryUrl, GURL(), delegate());
+ EXPECT_NE(kEntryUrl, delegate()->found_url_);
+ }
+
+ void Verify_FindNoMainResponse() {
+ EXPECT_EQ(kEntryUrl, delegate()->found_url_);
+ EXPECT_TRUE(delegate()->found_manifest_url_.is_empty());
+ EXPECT_EQ(kNoCacheId, delegate()->found_cache_id_);
+ EXPECT_EQ(kNoResponseId, delegate()->found_entry_.response_id());
+ EXPECT_EQ(kNoResponseId, delegate()->found_fallback_entry_.response_id());
+ EXPECT_TRUE(delegate()->found_namespace_entry_url_.is_empty());
+ EXPECT_EQ(0, delegate()->found_entry_.types());
+ EXPECT_EQ(0, delegate()->found_fallback_entry_.types());
+ TestFinished();
+ }
+
+ // BasicFindMainResponse -------------------------------
+
+ void BasicFindMainResponseInDatabase() {
+ BasicFindMainResponse(true);
+ }
+
+ void BasicFindMainResponseInWorkingSet() {
+ BasicFindMainResponse(false);
+ }
+
+ void BasicFindMainResponse(bool drop_from_working_set) {
+ PushNextTask(base::Bind(
+ &AppCacheStorageImplTest::Verify_BasicFindMainResponse,
+ base::Unretained(this)));
+
+ // Setup some preconditions. Create a complete cache with an entry
+ // in storage.
+ MakeCacheAndGroup(kManifestUrl, 2, 1, true);
+ cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::EXPLICIT, 1));
+ AppCacheDatabase::EntryRecord entry_record;
+ entry_record.cache_id = 1;
+ entry_record.url = kEntryUrl;
+ entry_record.flags = AppCacheEntry::EXPLICIT;
+ entry_record.response_id = 1;
+ EXPECT_TRUE(database()->InsertEntry(&entry_record));
+
+ // Optionally drop the cache/group pair from the working set.
+ if (drop_from_working_set) {
+ EXPECT_TRUE(cache_->HasOneRef());
+ cache_ = NULL;
+ EXPECT_TRUE(group_->HasOneRef());
+ group_ = NULL;
+ }
+
+ // Conduct the test.
+ storage()->FindResponseForMainRequest(kEntryUrl, GURL(), delegate());
+ EXPECT_NE(kEntryUrl, delegate()->found_url_);
+ }
+
+ void Verify_BasicFindMainResponse() {
+ EXPECT_EQ(kEntryUrl, delegate()->found_url_);
+ EXPECT_EQ(kManifestUrl, delegate()->found_manifest_url_);
+ EXPECT_EQ(1, delegate()->found_cache_id_);
+ EXPECT_EQ(2, delegate()->found_group_id_);
+ EXPECT_EQ(1, delegate()->found_entry_.response_id());
+ EXPECT_TRUE(delegate()->found_entry_.IsExplicit());
+ EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id());
+ TestFinished();
+ }
+
+ // BasicFindMainFallbackResponse -------------------------------
+
+ void BasicFindMainFallbackResponseInDatabase() {
+ BasicFindMainFallbackResponse(true);
+ }
+
+ void BasicFindMainFallbackResponseInWorkingSet() {
+ BasicFindMainFallbackResponse(false);
+ }
+
+ void BasicFindMainFallbackResponse(bool drop_from_working_set) {
+ PushNextTask(base::Bind(
+ &AppCacheStorageImplTest::Verify_BasicFindMainFallbackResponse,
+ base::Unretained(this)));
+
+ // Setup some preconditions. Create a complete cache with a
+ // fallback namespace and entry.
+ MakeCacheAndGroup(kManifestUrl, 2, 1, true);
+ cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::FALLBACK, 1));
+ cache_->AddEntry(kEntryUrl2, AppCacheEntry(AppCacheEntry::FALLBACK, 2));
+ cache_->fallback_namespaces_.push_back(
+ Namespace(FALLBACK_NAMESPACE, kFallbackNamespace2, kEntryUrl2, false));
+ cache_->fallback_namespaces_.push_back(
+ Namespace(FALLBACK_NAMESPACE, kFallbackNamespace, kEntryUrl, false));
+ AppCacheDatabase::CacheRecord cache_record;
+ std::vector<AppCacheDatabase::EntryRecord> entries;
+ std::vector<AppCacheDatabase::NamespaceRecord> intercepts;
+ std::vector<AppCacheDatabase::NamespaceRecord> fallbacks;
+ std::vector<AppCacheDatabase::OnlineWhiteListRecord> whitelists;
+ cache_->ToDatabaseRecords(group_.get(),
+ &cache_record,
+ &entries,
+ &intercepts,
+ &fallbacks,
+ &whitelists);
+
+ std::vector<AppCacheDatabase::EntryRecord>::const_iterator iter =
+ entries.begin();
+ while (iter != entries.end()) {
+ // MakeCacheAndGroup has inserted the default entry record already.
+ if (iter->url != kDefaultEntryUrl)
+ EXPECT_TRUE(database()->InsertEntry(&(*iter)));
+ ++iter;
+ }
+
+ EXPECT_TRUE(database()->InsertNamespaceRecords(fallbacks));
+ EXPECT_TRUE(database()->InsertOnlineWhiteListRecords(whitelists));
+ if (drop_from_working_set) {
+ EXPECT_TRUE(cache_->HasOneRef());
+ cache_ = NULL;
+ EXPECT_TRUE(group_->HasOneRef());
+ group_ = NULL;
+ }
+
+ // Conduct the test. The test url is in both fallback namespace urls,
+ // but should match the longer of the two.
+ storage()->FindResponseForMainRequest(kFallbackTestUrl, GURL(), delegate());
+ EXPECT_NE(kFallbackTestUrl, delegate()->found_url_);
+ }
+
+ void Verify_BasicFindMainFallbackResponse() {
+ EXPECT_EQ(kFallbackTestUrl, delegate()->found_url_);
+ EXPECT_EQ(kManifestUrl, delegate()->found_manifest_url_);
+ EXPECT_EQ(1, delegate()->found_cache_id_);
+ EXPECT_EQ(2, delegate()->found_group_id_);
+ EXPECT_FALSE(delegate()->found_entry_.has_response_id());
+ EXPECT_EQ(2, delegate()->found_fallback_entry_.response_id());
+ EXPECT_EQ(kEntryUrl2, delegate()->found_namespace_entry_url_);
+ EXPECT_TRUE(delegate()->found_fallback_entry_.IsFallback());
+ TestFinished();
+ }
+
+ // BasicFindMainInterceptResponse -------------------------------
+
+ void BasicFindMainInterceptResponseInDatabase() {
+ BasicFindMainInterceptResponse(true);
+ }
+
+ void BasicFindMainInterceptResponseInWorkingSet() {
+ BasicFindMainInterceptResponse(false);
+ }
+
+ void BasicFindMainInterceptResponse(bool drop_from_working_set) {
+ PushNextTask(base::Bind(
+ &AppCacheStorageImplTest::Verify_BasicFindMainInterceptResponse,
+ base::Unretained(this)));
+
+ // Setup some preconditions. Create a complete cache with an
+ // intercept namespace and entry.
+ MakeCacheAndGroup(kManifestUrl, 2, 1, true);
+ cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::INTERCEPT, 1));
+ cache_->AddEntry(kEntryUrl2, AppCacheEntry(AppCacheEntry::INTERCEPT, 2));
+ cache_->intercept_namespaces_.push_back(
+ Namespace(INTERCEPT_NAMESPACE, kInterceptNamespace2,
+ kEntryUrl2, false));
+ cache_->intercept_namespaces_.push_back(
+ Namespace(INTERCEPT_NAMESPACE, kInterceptNamespace,
+ kEntryUrl, false));
+ AppCacheDatabase::CacheRecord cache_record;
+ std::vector<AppCacheDatabase::EntryRecord> entries;
+ std::vector<AppCacheDatabase::NamespaceRecord> intercepts;
+ std::vector<AppCacheDatabase::NamespaceRecord> fallbacks;
+ std::vector<AppCacheDatabase::OnlineWhiteListRecord> whitelists;
+ cache_->ToDatabaseRecords(group_.get(),
+ &cache_record,
+ &entries,
+ &intercepts,
+ &fallbacks,
+ &whitelists);
+
+ std::vector<AppCacheDatabase::EntryRecord>::const_iterator iter =
+ entries.begin();
+ while (iter != entries.end()) {
+ // MakeCacheAndGroup has inserted the default entry record already
+ if (iter->url != kDefaultEntryUrl)
+ EXPECT_TRUE(database()->InsertEntry(&(*iter)));
+ ++iter;
+ }
+
+ EXPECT_TRUE(database()->InsertNamespaceRecords(intercepts));
+ EXPECT_TRUE(database()->InsertOnlineWhiteListRecords(whitelists));
+ if (drop_from_working_set) {
+ EXPECT_TRUE(cache_->HasOneRef());
+ cache_ = NULL;
+ EXPECT_TRUE(group_->HasOneRef());
+ group_ = NULL;
+ }
+
+ // Conduct the test. The test url is in both intercept namespaces,
+ // but should match the longer of the two.
+ storage()->FindResponseForMainRequest(
+ kInterceptTestUrl, GURL(), delegate());
+ EXPECT_NE(kInterceptTestUrl, delegate()->found_url_);
+ }
+
+ void Verify_BasicFindMainInterceptResponse() {
+ EXPECT_EQ(kInterceptTestUrl, delegate()->found_url_);
+ EXPECT_EQ(kManifestUrl, delegate()->found_manifest_url_);
+ EXPECT_EQ(1, delegate()->found_cache_id_);
+ EXPECT_EQ(2, delegate()->found_group_id_);
+ EXPECT_EQ(2, delegate()->found_entry_.response_id());
+ EXPECT_TRUE(delegate()->found_entry_.IsIntercept());
+ EXPECT_EQ(kEntryUrl2, delegate()->found_namespace_entry_url_);
+ EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id());
+ TestFinished();
+ }
+
+ // FindInterceptPatternMatch ----------------------------------------
+
+ void FindInterceptPatternMatchInDatabase() {
+ FindInterceptPatternMatch(true);
+ }
+
+ void FindInterceptPatternMatchInWorkingSet() {
+ FindInterceptPatternMatch(false);
+ }
+
+ void FindInterceptPatternMatch(bool drop_from_working_set) {
+ // Setup some preconditions. Create a complete cache with an
+ // pattern matching intercept namespace and entry.
+ MakeCacheAndGroup(kManifestUrl, 2, 1, true);
+ cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::INTERCEPT, 1));
+ cache_->intercept_namespaces_.push_back(
+ Namespace(INTERCEPT_NAMESPACE, kInterceptPatternNamespace,
+ kEntryUrl, true));
+ AppCacheDatabase::CacheRecord cache_record;
+ std::vector<AppCacheDatabase::EntryRecord> entries;
+ std::vector<AppCacheDatabase::NamespaceRecord> intercepts;
+ std::vector<AppCacheDatabase::NamespaceRecord> fallbacks;
+ std::vector<AppCacheDatabase::OnlineWhiteListRecord> whitelists;
+ cache_->ToDatabaseRecords(group_.get(),
+ &cache_record,
+ &entries,
+ &intercepts,
+ &fallbacks,
+ &whitelists);
+
+ std::vector<AppCacheDatabase::EntryRecord>::const_iterator iter =
+ entries.begin();
+ while (iter != entries.end()) {
+ // MakeCacheAndGroup has inserted the default entry record already
+ if (iter->url != kDefaultEntryUrl)
+ EXPECT_TRUE(database()->InsertEntry(&(*iter)));
+ ++iter;
+ }
+
+ EXPECT_TRUE(database()->InsertNamespaceRecords(intercepts));
+ if (drop_from_working_set) {
+ EXPECT_TRUE(cache_->HasOneRef());
+ cache_ = NULL;
+ EXPECT_TRUE(group_->HasOneRef());
+ group_ = NULL;
+ }
+
+ // First test something that does not match the pattern.
+ PushNextTask(base::Bind(
+ &AppCacheStorageImplTest::Verify_FindInterceptPatternMatchNegative,
+ base::Unretained(this)));
+ storage()->FindResponseForMainRequest(
+ kInterceptPatternTestNegativeUrl, GURL(), delegate());
+ EXPECT_EQ(GURL(), delegate()->found_url_); // Is always async.
+ }
+
+ void Verify_FindInterceptPatternMatchNegative() {
+ EXPECT_EQ(kInterceptPatternTestNegativeUrl, delegate()->found_url_);
+ EXPECT_TRUE(delegate()->found_manifest_url_.is_empty());
+ EXPECT_EQ(kNoCacheId, delegate()->found_cache_id_);
+ EXPECT_EQ(kNoResponseId, delegate()->found_entry_.response_id());
+ EXPECT_EQ(kNoResponseId, delegate()->found_fallback_entry_.response_id());
+ EXPECT_TRUE(delegate()->found_namespace_entry_url_.is_empty());
+ EXPECT_EQ(0, delegate()->found_entry_.types());
+ EXPECT_EQ(0, delegate()->found_fallback_entry_.types());
+
+ // Then test something that matches.
+ PushNextTask(base::Bind(
+ &AppCacheStorageImplTest::Verify_FindInterceptPatternMatchPositive,
+ base::Unretained(this)));
+ storage()->FindResponseForMainRequest(
+ kInterceptPatternTestPositiveUrl, GURL(), delegate());
+ }
+
+ void Verify_FindInterceptPatternMatchPositive() {
+ EXPECT_EQ(kInterceptPatternTestPositiveUrl, delegate()->found_url_);
+ EXPECT_EQ(kManifestUrl, delegate()->found_manifest_url_);
+ EXPECT_EQ(1, delegate()->found_cache_id_);
+ EXPECT_EQ(2, delegate()->found_group_id_);
+ EXPECT_EQ(1, delegate()->found_entry_.response_id());
+ EXPECT_TRUE(delegate()->found_entry_.IsIntercept());
+ EXPECT_EQ(kEntryUrl, delegate()->found_namespace_entry_url_);
+ EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id());
+ TestFinished();
+ }
+
+ // FindFallbackPatternMatch -------------------------------
+
+ void FindFallbackPatternMatchInDatabase() {
+ FindFallbackPatternMatch(true);
+ }
+
+ void FindFallbackPatternMatchInWorkingSet() {
+ FindFallbackPatternMatch(false);
+ }
+
+ void FindFallbackPatternMatch(bool drop_from_working_set) {
+ // Setup some preconditions. Create a complete cache with a
+ // pattern matching fallback namespace and entry.
+ MakeCacheAndGroup(kManifestUrl, 2, 1, true);
+ cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::FALLBACK, 1));
+ cache_->fallback_namespaces_.push_back(
+ Namespace(FALLBACK_NAMESPACE, kFallbackPatternNamespace,
+ kEntryUrl, true));
+ AppCacheDatabase::CacheRecord cache_record;
+ std::vector<AppCacheDatabase::EntryRecord> entries;
+ std::vector<AppCacheDatabase::NamespaceRecord> intercepts;
+ std::vector<AppCacheDatabase::NamespaceRecord> fallbacks;
+ std::vector<AppCacheDatabase::OnlineWhiteListRecord> whitelists;
+ cache_->ToDatabaseRecords(group_.get(),
+ &cache_record,
+ &entries,
+ &intercepts,
+ &fallbacks,
+ &whitelists);
+
+ std::vector<AppCacheDatabase::EntryRecord>::const_iterator iter =
+ entries.begin();
+ while (iter != entries.end()) {
+ // MakeCacheAndGroup has inserted the default entry record already.
+ if (iter->url != kDefaultEntryUrl)
+ EXPECT_TRUE(database()->InsertEntry(&(*iter)));
+ ++iter;
+ }
+
+ EXPECT_TRUE(database()->InsertNamespaceRecords(fallbacks));
+ if (drop_from_working_set) {
+ EXPECT_TRUE(cache_->HasOneRef());
+ cache_ = NULL;
+ EXPECT_TRUE(group_->HasOneRef());
+ group_ = NULL;
+ }
+
+ // First test something that does not match the pattern.
+ PushNextTask(base::Bind(
+ &AppCacheStorageImplTest::Verify_FindFallbackPatternMatchNegative,
+ base::Unretained(this)));
+ storage()->FindResponseForMainRequest(
+ kFallbackPatternTestNegativeUrl, GURL(), delegate());
+ EXPECT_EQ(GURL(), delegate()->found_url_); // Is always async.
+ }
+
+ void Verify_FindFallbackPatternMatchNegative() {
+ EXPECT_EQ(kFallbackPatternTestNegativeUrl, delegate()->found_url_);
+ EXPECT_TRUE(delegate()->found_manifest_url_.is_empty());
+ EXPECT_EQ(kNoCacheId, delegate()->found_cache_id_);
+ EXPECT_EQ(kNoResponseId, delegate()->found_entry_.response_id());
+ EXPECT_EQ(kNoResponseId, delegate()->found_fallback_entry_.response_id());
+ EXPECT_TRUE(delegate()->found_namespace_entry_url_.is_empty());
+ EXPECT_EQ(0, delegate()->found_entry_.types());
+ EXPECT_EQ(0, delegate()->found_fallback_entry_.types());
+
+ // Then test something that matches.
+ PushNextTask(base::Bind(
+ &AppCacheStorageImplTest::Verify_FindFallbackPatternMatchPositive,
+ base::Unretained(this)));
+ storage()->FindResponseForMainRequest(
+ kFallbackPatternTestPositiveUrl, GURL(), delegate());
+ }
+
+ void Verify_FindFallbackPatternMatchPositive() {
+ EXPECT_EQ(kFallbackPatternTestPositiveUrl, delegate()->found_url_);
+ EXPECT_EQ(kManifestUrl, delegate()->found_manifest_url_);
+ EXPECT_EQ(1, delegate()->found_cache_id_);
+ EXPECT_EQ(2, delegate()->found_group_id_);
+ EXPECT_EQ(1, delegate()->found_fallback_entry_.response_id());
+ EXPECT_TRUE(delegate()->found_fallback_entry_.IsFallback());
+ EXPECT_EQ(kEntryUrl, delegate()->found_namespace_entry_url_);
+ EXPECT_FALSE(delegate()->found_entry_.has_response_id());
+ TestFinished();
+ }
+
+ // FindMainResponseWithMultipleHits -------------------------------
+
+ void FindMainResponseWithMultipleHits() {
+ PushNextTask(base::Bind(
+ &AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits,
+ base::Unretained(this)));
+
+ // Setup some preconditions, create a few caches with an identical set
+ // of entries and fallback namespaces. Only the last one remains in
+ // the working set to simulate appearing as "in use".
+ MakeMultipleHitCacheAndGroup(kManifestUrl, 1);
+ MakeMultipleHitCacheAndGroup(kManifestUrl2, 2);
+ MakeMultipleHitCacheAndGroup(kManifestUrl3, 3);
+
+ // Conduct the test, we should find the response from the last cache
+ // since it's "in use".
+ storage()->FindResponseForMainRequest(kEntryUrl, GURL(), delegate());
+ EXPECT_NE(kEntryUrl, delegate()->found_url_);
+ }
+
+ void MakeMultipleHitCacheAndGroup(const GURL& manifest_url, int id) {
+ MakeCacheAndGroup(manifest_url, id, id, true);
+ AppCacheDatabase::EntryRecord entry_record;
+
+ // Add an entry for kEntryUrl
+ entry_record.cache_id = id;
+ entry_record.url = kEntryUrl;
+ entry_record.flags = AppCacheEntry::EXPLICIT;
+ entry_record.response_id = id;
+ EXPECT_TRUE(database()->InsertEntry(&entry_record));
+ cache_->AddEntry(
+ entry_record.url,
+ AppCacheEntry(entry_record.flags, entry_record.response_id));
+
+ // Add an entry for the manifestUrl
+ entry_record.cache_id = id;
+ entry_record.url = manifest_url;
+ entry_record.flags = AppCacheEntry::MANIFEST;
+ entry_record.response_id = id + kManifestEntryIdOffset;
+ EXPECT_TRUE(database()->InsertEntry(&entry_record));
+ cache_->AddEntry(
+ entry_record.url,
+ AppCacheEntry(entry_record.flags, entry_record.response_id));
+
+ // Add a fallback entry and namespace
+ entry_record.cache_id = id;
+ entry_record.url = kEntryUrl2;
+ entry_record.flags = AppCacheEntry::FALLBACK;
+ entry_record.response_id = id + kFallbackEntryIdOffset;
+ EXPECT_TRUE(database()->InsertEntry(&entry_record));
+ cache_->AddEntry(
+ entry_record.url,
+ AppCacheEntry(entry_record.flags, entry_record.response_id));
+ AppCacheDatabase::NamespaceRecord fallback_namespace_record;
+ fallback_namespace_record.cache_id = id;
+ fallback_namespace_record.namespace_.target_url = entry_record.url;
+ fallback_namespace_record.namespace_.namespace_url = kFallbackNamespace;
+ fallback_namespace_record.origin = manifest_url.GetOrigin();
+ EXPECT_TRUE(database()->InsertNamespace(&fallback_namespace_record));
+ cache_->fallback_namespaces_.push_back(
+ Namespace(FALLBACK_NAMESPACE, kFallbackNamespace, kEntryUrl2, false));
+ }
+
+ void Verify_FindMainResponseWithMultipleHits() {
+ EXPECT_EQ(kEntryUrl, delegate()->found_url_);
+ EXPECT_EQ(kManifestUrl3, delegate()->found_manifest_url_);
+ EXPECT_EQ(3, delegate()->found_cache_id_);
+ EXPECT_EQ(3, delegate()->found_group_id_);
+ EXPECT_EQ(3, delegate()->found_entry_.response_id());
+ EXPECT_TRUE(delegate()->found_entry_.IsExplicit());
+ EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id());
+
+ // Conduct another test perferring kManifestUrl
+ delegate_.reset(new MockStorageDelegate(this));
+ PushNextTask(base::Bind(
+ &AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits2,
+ base::Unretained(this)));
+ storage()->FindResponseForMainRequest(kEntryUrl, kManifestUrl, delegate());
+ EXPECT_NE(kEntryUrl, delegate()->found_url_);
+ }
+
+ void Verify_FindMainResponseWithMultipleHits2() {
+ EXPECT_EQ(kEntryUrl, delegate()->found_url_);
+ EXPECT_EQ(kManifestUrl, delegate()->found_manifest_url_);
+ EXPECT_EQ(1, delegate()->found_cache_id_);
+ EXPECT_EQ(1, delegate()->found_group_id_);
+ EXPECT_EQ(1, delegate()->found_entry_.response_id());
+ EXPECT_TRUE(delegate()->found_entry_.IsExplicit());
+ EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id());
+
+ // Conduct the another test perferring kManifestUrl2
+ delegate_.reset(new MockStorageDelegate(this));
+ PushNextTask(base::Bind(
+ &AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits3,
+ base::Unretained(this)));
+ storage()->FindResponseForMainRequest(kEntryUrl, kManifestUrl2, delegate());
+ EXPECT_NE(kEntryUrl, delegate()->found_url_);
+ }
+
+ void Verify_FindMainResponseWithMultipleHits3() {
+ EXPECT_EQ(kEntryUrl, delegate()->found_url_);
+ EXPECT_EQ(kManifestUrl2, delegate()->found_manifest_url_);
+ EXPECT_EQ(2, delegate()->found_cache_id_);
+ EXPECT_EQ(2, delegate()->found_group_id_);
+ EXPECT_EQ(2, delegate()->found_entry_.response_id());
+ EXPECT_TRUE(delegate()->found_entry_.IsExplicit());
+ EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id());
+
+ // Conduct another test with no preferred manifest that hits the fallback.
+ delegate_.reset(new MockStorageDelegate(this));
+ PushNextTask(base::Bind(
+ &AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits4,
+ base::Unretained(this)));
+ storage()->FindResponseForMainRequest(
+ kFallbackTestUrl, GURL(), delegate());
+ EXPECT_NE(kFallbackTestUrl, delegate()->found_url_);
+ }
+
+ void Verify_FindMainResponseWithMultipleHits4() {
+ EXPECT_EQ(kFallbackTestUrl, delegate()->found_url_);
+ EXPECT_EQ(kManifestUrl3, delegate()->found_manifest_url_);
+ EXPECT_EQ(3, delegate()->found_cache_id_);
+ EXPECT_EQ(3, delegate()->found_group_id_);
+ EXPECT_FALSE(delegate()->found_entry_.has_response_id());
+ EXPECT_EQ(3 + kFallbackEntryIdOffset,
+ delegate()->found_fallback_entry_.response_id());
+ EXPECT_TRUE(delegate()->found_fallback_entry_.IsFallback());
+ EXPECT_EQ(kEntryUrl2, delegate()->found_namespace_entry_url_);
+
+ // Conduct another test preferring kManifestUrl2 that hits the fallback.
+ delegate_.reset(new MockStorageDelegate(this));
+ PushNextTask(base::Bind(
+ &AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits5,
+ base::Unretained(this)));
+ storage()->FindResponseForMainRequest(
+ kFallbackTestUrl, kManifestUrl2, delegate());
+ EXPECT_NE(kFallbackTestUrl, delegate()->found_url_);
+ }
+
+ void Verify_FindMainResponseWithMultipleHits5() {
+ EXPECT_EQ(kFallbackTestUrl, delegate()->found_url_);
+ EXPECT_EQ(kManifestUrl2, delegate()->found_manifest_url_);
+ EXPECT_EQ(2, delegate()->found_cache_id_);
+ EXPECT_EQ(2, delegate()->found_group_id_);
+ EXPECT_FALSE(delegate()->found_entry_.has_response_id());
+ EXPECT_EQ(2 + kFallbackEntryIdOffset,
+ delegate()->found_fallback_entry_.response_id());
+ EXPECT_TRUE(delegate()->found_fallback_entry_.IsFallback());
+ EXPECT_EQ(kEntryUrl2, delegate()->found_namespace_entry_url_);
+
+ TestFinished();
+ }
+
+ // FindMainResponseExclusions -------------------------------
+
+ void FindMainResponseExclusionsInDatabase() {
+ FindMainResponseExclusions(true);
+ }
+
+ void FindMainResponseExclusionsInWorkingSet() {
+ FindMainResponseExclusions(false);
+ }
+
+ void FindMainResponseExclusions(bool drop_from_working_set) {
+ // Setup some preconditions. Create a complete cache with a
+ // foreign entry, an online namespace, and a second online
+ // namespace nested within a fallback namespace.
+ MakeCacheAndGroup(kManifestUrl, 1, 1, true);
+ cache_->AddEntry(kEntryUrl,
+ AppCacheEntry(AppCacheEntry::EXPLICIT | AppCacheEntry::FOREIGN, 1));
+ cache_->AddEntry(kEntryUrl2, AppCacheEntry(AppCacheEntry::FALLBACK, 2));
+ cache_->fallback_namespaces_.push_back(
+ Namespace(FALLBACK_NAMESPACE, kFallbackNamespace, kEntryUrl2, false));
+ cache_->online_whitelist_namespaces_.push_back(
+ Namespace(NETWORK_NAMESPACE, kOnlineNamespace,
+ GURL(), false));
+ cache_->online_whitelist_namespaces_.push_back(
+ Namespace(NETWORK_NAMESPACE, kOnlineNamespaceWithinFallback,
+ GURL(), false));
+
+ AppCacheDatabase::EntryRecord entry_record;
+ entry_record.cache_id = 1;
+ entry_record.url = kEntryUrl;
+ entry_record.flags = AppCacheEntry::EXPLICIT | AppCacheEntry::FOREIGN;
+ entry_record.response_id = 1;
+ EXPECT_TRUE(database()->InsertEntry(&entry_record));
+ AppCacheDatabase::OnlineWhiteListRecord whitelist_record;
+ whitelist_record.cache_id = 1;
+ whitelist_record.namespace_url = kOnlineNamespace;
+ EXPECT_TRUE(database()->InsertOnlineWhiteList(&whitelist_record));
+ AppCacheDatabase::NamespaceRecord fallback_namespace_record;
+ fallback_namespace_record.cache_id = 1;
+ fallback_namespace_record.namespace_.target_url = kEntryUrl2;
+ fallback_namespace_record.namespace_.namespace_url = kFallbackNamespace;
+ fallback_namespace_record.origin = kManifestUrl.GetOrigin();
+ EXPECT_TRUE(database()->InsertNamespace(&fallback_namespace_record));
+ whitelist_record.cache_id = 1;
+ whitelist_record.namespace_url = kOnlineNamespaceWithinFallback;
+ EXPECT_TRUE(database()->InsertOnlineWhiteList(&whitelist_record));
+ if (drop_from_working_set) {
+ cache_ = NULL;
+ group_ = NULL;
+ }
+
+ // We should not find anything for the foreign entry.
+ PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_ExclusionNotFound,
+ base::Unretained(this), kEntryUrl, 1));
+ storage()->FindResponseForMainRequest(kEntryUrl, GURL(), delegate());
+ }
+
+ void Verify_ExclusionNotFound(GURL expected_url, int phase) {
+ EXPECT_EQ(expected_url, delegate()->found_url_);
+ EXPECT_TRUE(delegate()->found_manifest_url_.is_empty());
+ EXPECT_EQ(kNoCacheId, delegate()->found_cache_id_);
+ EXPECT_EQ(0, delegate()->found_group_id_);
+ EXPECT_EQ(kNoResponseId, delegate()->found_entry_.response_id());
+ EXPECT_EQ(kNoResponseId, delegate()->found_fallback_entry_.response_id());
+ EXPECT_TRUE(delegate()->found_namespace_entry_url_.is_empty());
+ EXPECT_EQ(0, delegate()->found_entry_.types());
+ EXPECT_EQ(0, delegate()->found_fallback_entry_.types());
+
+ if (phase == 1) {
+ // We should not find anything for the online namespace.
+ PushNextTask(
+ base::Bind(&AppCacheStorageImplTest::Verify_ExclusionNotFound,
+ base::Unretained(this), kOnlineNamespace, 2));
+ storage()->FindResponseForMainRequest(
+ kOnlineNamespace, GURL(), delegate());
+ return;
+ }
+ if (phase == 2) {
+ // We should not find anything for the online namespace nested within
+ // the fallback namespace.
+ PushNextTask(base::Bind(
+ &AppCacheStorageImplTest::Verify_ExclusionNotFound,
+ base::Unretained(this), kOnlineNamespaceWithinFallback, 3));
+ storage()->FindResponseForMainRequest(
+ kOnlineNamespaceWithinFallback, GURL(), delegate());
+ return;
+ }
+
+ TestFinished();
+ }
+
+ // Reinitialize -------------------------------
+ // These tests are somewhat of a system integration test.
+ // They rely on running a mock http server on our IO thread,
+ // and involves other appcache classes to get some code
+ // coverage thruout when Reinitialize happens.
+
+ class MockServiceObserver : public AppCacheService::Observer {
+ public:
+ explicit MockServiceObserver(AppCacheStorageImplTest* test)
+ : test_(test) {}
+
+ virtual void OnServiceReinitialized(
+ AppCacheStorageReference* old_storage_ref) OVERRIDE {
+ observed_old_storage_ = old_storage_ref;
+ test_->ScheduleNextTask();
+ }
+
+ scoped_refptr<AppCacheStorageReference> observed_old_storage_;
+ AppCacheStorageImplTest* test_;
+ };
+
+ class MockAppCacheFrontend : public AppCacheFrontend {
+ public:
+ MockAppCacheFrontend() : error_event_was_raised_(false) {}
+
+ virtual void OnCacheSelected(
+ int host_id, const AppCacheInfo& info) OVERRIDE {}
+ virtual void OnStatusChanged(const std::vector<int>& host_ids,
+ Status status) OVERRIDE {}
+ virtual void OnEventRaised(const std::vector<int>& host_ids,
+ EventID event_id) OVERRIDE {}
+ virtual void OnProgressEventRaised(
+ const std::vector<int>& host_ids,
+ const GURL& url,
+ int num_total, int num_complete) OVERRIDE {}
+ virtual void OnErrorEventRaised(const std::vector<int>& host_ids,
+ const ErrorDetails& details)
+ OVERRIDE {
+ error_event_was_raised_ = true;
+ }
+ virtual void OnLogMessage(int host_id, LogLevel log_level,
+ const std::string& message) OVERRIDE {}
+ virtual void OnContentBlocked(
+ int host_id, const GURL& manifest_url) OVERRIDE {}
+
+ bool error_event_was_raised_;
+ };
+
+ enum ReinitTestCase {
+ CORRUPT_CACHE_ON_INSTALL,
+ CORRUPT_CACHE_ON_LOAD_EXISTING,
+ CORRUPT_SQL_ON_INSTALL
+ };
+
+ void Reinitialize1() {
+ // Recover from a corrupt disk cache discovered while
+ // installing a new appcache.
+ Reinitialize(CORRUPT_CACHE_ON_INSTALL);
+ }
+
+ void Reinitialize2() {
+ // Recover from a corrupt disk cache discovered while
+ // trying to load a resource from an existing appcache.
+ Reinitialize(CORRUPT_CACHE_ON_LOAD_EXISTING);
+ }
+
+ void Reinitialize3() {
+ // Recover from a corrupt sql database discovered while
+ // installing a new appcache.
+ Reinitialize(CORRUPT_SQL_ON_INSTALL);
+ }
+
+ void Reinitialize(ReinitTestCase test_case) {
+ // Unlike all of the other tests, this one actually read/write files.
+ ASSERT_TRUE(temp_directory_.CreateUniqueTempDir());
+
+ AppCacheDatabase db(temp_directory_.path().AppendASCII("Index"));
+ EXPECT_TRUE(db.LazyOpen(true));
+
+ if (test_case == CORRUPT_CACHE_ON_INSTALL ||
+ test_case == CORRUPT_CACHE_ON_LOAD_EXISTING) {
+ // Create a corrupt/unopenable disk_cache index file.
+ const std::string kCorruptData("deadbeef");
+ base::FilePath disk_cache_directory =
+ temp_directory_.path().AppendASCII("Cache");
+ ASSERT_TRUE(base::CreateDirectory(disk_cache_directory));
+ base::FilePath index_file = disk_cache_directory.AppendASCII("index");
+ EXPECT_EQ(static_cast<int>(kCorruptData.length()),
+ base::WriteFile(
+ index_file, kCorruptData.data(), kCorruptData.length()));
+ }
+
+ // Create records for a degenerate cached manifest that only contains
+ // one entry for the manifest file resource.
+ if (test_case == CORRUPT_CACHE_ON_LOAD_EXISTING) {
+ AppCacheDatabase db(temp_directory_.path().AppendASCII("Index"));
+ GURL manifest_url = MockHttpServer::GetMockUrl("manifest");
+
+ AppCacheDatabase::GroupRecord group_record;
+ group_record.group_id = 1;
+ group_record.manifest_url = manifest_url;
+ group_record.origin = manifest_url.GetOrigin();
+ EXPECT_TRUE(db.InsertGroup(&group_record));
+ AppCacheDatabase::CacheRecord cache_record;
+ cache_record.cache_id = 1;
+ cache_record.group_id = 1;
+ cache_record.online_wildcard = false;
+ cache_record.update_time = kZeroTime;
+ cache_record.cache_size = kDefaultEntrySize;
+ EXPECT_TRUE(db.InsertCache(&cache_record));
+ AppCacheDatabase::EntryRecord entry_record;
+ entry_record.cache_id = 1;
+ entry_record.url = manifest_url;
+ entry_record.flags = AppCacheEntry::MANIFEST;
+ entry_record.response_id = 1;
+ entry_record.response_size = kDefaultEntrySize;
+ EXPECT_TRUE(db.InsertEntry(&entry_record));
+ }
+
+ // Recreate the service to point at the db and corruption on disk.
+ service_.reset(new AppCacheService(NULL));
+ service_->set_request_context(io_thread->request_context());
+ service_->Initialize(
+ temp_directory_.path(),
+ db_thread->message_loop_proxy().get(),
+ db_thread->message_loop_proxy().get());
+ mock_quota_manager_proxy_ = new MockQuotaManagerProxy();
+ service_->quota_manager_proxy_ = mock_quota_manager_proxy_;
+ delegate_.reset(new MockStorageDelegate(this));
+
+ // Additional setup to observe reinitailize happens.
+ observer_.reset(new MockServiceObserver(this));
+ service_->AddObserver(observer_.get());
+
+ // We continue after the init task is complete including the callback
+ // on the current thread.
+ FlushDbThreadTasks();
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&AppCacheStorageImplTest::Continue_Reinitialize,
+ base::Unretained(this),
+ test_case));
+ }
+
+ void Continue_Reinitialize(ReinitTestCase test_case) {
+ const int kMockProcessId = 1;
+ backend_.reset(new AppCacheBackendImpl);
+ backend_->Initialize(service_.get(), &frontend_, kMockProcessId);
+
+ if (test_case == CORRUPT_SQL_ON_INSTALL) {
+ // Break the db file
+ EXPECT_FALSE(database()->was_corruption_detected());
+ ASSERT_TRUE(sql::test::CorruptSizeInHeader(
+ temp_directory_.path().AppendASCII("Index")));
+ }
+
+ if (test_case == CORRUPT_CACHE_ON_INSTALL ||
+ test_case == CORRUPT_SQL_ON_INSTALL) {
+ // Try to create a new appcache, the resulting update job will
+ // eventually fail when it gets to disk cache initialization.
+ backend_->RegisterHost(1);
+ AppCacheHost* host1 = backend_->GetHost(1);
+ const GURL kEmptyPageUrl(MockHttpServer::GetMockUrl("empty.html"));
+ host1->first_party_url_ = kEmptyPageUrl;
+ host1->SelectCache(kEmptyPageUrl,
+ kNoCacheId,
+ MockHttpServer::GetMockUrl("manifest"));
+ } else {
+ ASSERT_EQ(CORRUPT_CACHE_ON_LOAD_EXISTING, test_case);
+ // Try to access the existing cache manifest.
+ // The URLRequestJob will eventually fail when it gets to disk
+ // cache initialization.
+ backend_->RegisterHost(2);
+ AppCacheHost* host2 = backend_->GetHost(2);
+ GURL manifest_url = MockHttpServer::GetMockUrl("manifest");
+ request_ = service()->request_context()->CreateRequest(
+ manifest_url, net::DEFAULT_PRIORITY, NULL, NULL);
+ AppCacheInterceptor::SetExtraRequestInfo(
+ request_.get(), service_.get(),
+ backend_->process_id(), host2->host_id(),
+ ResourceType::MAIN_FRAME);
+ request_->Start();
+ }
+
+ PushNextTask(base::Bind(
+ &AppCacheStorageImplTest::Verify_Reinitialized,
+ base::Unretained(this),
+ test_case));
+ }
+
+ void Verify_Reinitialized(ReinitTestCase test_case) {
+ // Verify we got notified of reinit and a new storage instance is created,
+ // and that the old data has been deleted.
+ EXPECT_TRUE(observer_->observed_old_storage_.get());
+ EXPECT_TRUE(observer_->observed_old_storage_->storage() != storage());
+ EXPECT_FALSE(PathExists(
+ temp_directory_.path().AppendASCII("Cache").AppendASCII("index")));
+ EXPECT_FALSE(PathExists(
+ temp_directory_.path().AppendASCII("Index")));
+
+ if (test_case == CORRUPT_SQL_ON_INSTALL) {
+ AppCacheStorageImpl* storage = static_cast<AppCacheStorageImpl*>(
+ observer_->observed_old_storage_->storage());
+ EXPECT_TRUE(storage->database_->was_corruption_detected());
+ }
+
+ // Verify that the hosts saw appropriate events.
+ if (test_case == CORRUPT_CACHE_ON_INSTALL ||
+ test_case == CORRUPT_SQL_ON_INSTALL) {
+ EXPECT_TRUE(frontend_.error_event_was_raised_);
+ AppCacheHost* host1 = backend_->GetHost(1);
+ EXPECT_FALSE(host1->associated_cache());
+ EXPECT_FALSE(host1->group_being_updated_);
+ EXPECT_TRUE(host1->disabled_storage_reference_.get());
+ } else {
+ ASSERT_EQ(CORRUPT_CACHE_ON_LOAD_EXISTING, test_case);
+ AppCacheHost* host2 = backend_->GetHost(2);
+ EXPECT_EQ(1, host2->main_resource_cache_->cache_id());
+ EXPECT_TRUE(host2->disabled_storage_reference_.get());
+ }
+
+ // Cleanup and claim victory.
+ service_->RemoveObserver(observer_.get());
+ request_.reset();
+ backend_.reset();
+ observer_.reset();
+ TestFinished();
+ }
+
+ // Test case helpers --------------------------------------------------
+
+ AppCacheService* service() {
+ return service_.get();
+ }
+
+ AppCacheStorageImpl* storage() {
+ return static_cast<AppCacheStorageImpl*>(service()->storage());
+ }
+
+ AppCacheDatabase* database() {
+ return storage()->database_;
+ }
+
+ MockStorageDelegate* delegate() {
+ return delegate_.get();
+ }
+
+ void MakeCacheAndGroup(
+ const GURL& manifest_url, int64 group_id, int64 cache_id,
+ bool add_to_database) {
+ AppCacheEntry default_entry(
+ AppCacheEntry::EXPLICIT, cache_id + kDefaultEntryIdOffset,
+ kDefaultEntrySize);
+ group_ = new AppCacheGroup(storage(), manifest_url, group_id);
+ cache_ = new AppCache(storage(), cache_id);
+ cache_->AddEntry(kDefaultEntryUrl, default_entry);
+ cache_->set_complete(true);
+ group_->AddCache(cache_.get());
+ if (add_to_database) {
+ AppCacheDatabase::GroupRecord group_record;
+ group_record.group_id = group_id;
+ group_record.manifest_url = manifest_url;
+ group_record.origin = manifest_url.GetOrigin();
+ EXPECT_TRUE(database()->InsertGroup(&group_record));
+ AppCacheDatabase::CacheRecord cache_record;
+ cache_record.cache_id = cache_id;
+ cache_record.group_id = group_id;
+ cache_record.online_wildcard = false;
+ cache_record.update_time = kZeroTime;
+ cache_record.cache_size = kDefaultEntrySize;
+ EXPECT_TRUE(database()->InsertCache(&cache_record));
+ AppCacheDatabase::EntryRecord entry_record;
+ entry_record.cache_id = cache_id;
+ entry_record.url = kDefaultEntryUrl;
+ entry_record.flags = default_entry.types();
+ entry_record.response_id = default_entry.response_id();
+ entry_record.response_size = default_entry.response_size();
+ EXPECT_TRUE(database()->InsertEntry(&entry_record));
+
+ storage()->usage_map_[manifest_url.GetOrigin()] =
+ default_entry.response_size();
+ }
+ }
+
+ // Data members --------------------------------------------------
+
+ scoped_ptr<base::WaitableEvent> test_finished_event_;
+ std::stack<base::Closure> task_stack_;
+ scoped_ptr<AppCacheService> service_;
+ scoped_ptr<MockStorageDelegate> delegate_;
+ scoped_refptr<MockQuotaManagerProxy> mock_quota_manager_proxy_;
+ scoped_refptr<AppCacheGroup> group_;
+ scoped_refptr<AppCache> cache_;
+ scoped_refptr<AppCache> cache2_;
+
+ // Specifically for the Reinitalize test.
+ base::ScopedTempDir temp_directory_;
+ scoped_ptr<MockServiceObserver> observer_;
+ MockAppCacheFrontend frontend_;
+ scoped_ptr<AppCacheBackendImpl> backend_;
+ scoped_ptr<net::URLRequest> request_;
+};
+
+
+TEST_F(AppCacheStorageImplTest, LoadCache_Miss) {
+ RunTestOnIOThread(&AppCacheStorageImplTest::LoadCache_Miss);
+}
+
+TEST_F(AppCacheStorageImplTest, LoadCache_NearHit) {
+ RunTestOnIOThread(&AppCacheStorageImplTest::LoadCache_NearHit);
+}
+
+TEST_F(AppCacheStorageImplTest, CreateGroupInEmptyOrigin) {
+ RunTestOnIOThread(&AppCacheStorageImplTest::CreateGroupInEmptyOrigin);
+}
+
+TEST_F(AppCacheStorageImplTest, CreateGroupInPopulatedOrigin) {
+ RunTestOnIOThread(&AppCacheStorageImplTest::CreateGroupInPopulatedOrigin);
+}
+
+TEST_F(AppCacheStorageImplTest, LoadGroupAndCache_FarHit) {
+ RunTestOnIOThread(&AppCacheStorageImplTest::LoadGroupAndCache_FarHit);
+}
+
+TEST_F(AppCacheStorageImplTest, StoreNewGroup) {
+ RunTestOnIOThread(&AppCacheStorageImplTest::StoreNewGroup);
+}
+
+TEST_F(AppCacheStorageImplTest, StoreExistingGroup) {
+ RunTestOnIOThread(&AppCacheStorageImplTest::StoreExistingGroup);
+}
+
+TEST_F(AppCacheStorageImplTest, StoreExistingGroupExistingCache) {
+ RunTestOnIOThread(&AppCacheStorageImplTest::StoreExistingGroupExistingCache);
+}
+
+TEST_F(AppCacheStorageImplTest, FailStoreGroup) {
+ RunTestOnIOThread(&AppCacheStorageImplTest::FailStoreGroup);
+}
+
+TEST_F(AppCacheStorageImplTest, MakeGroupObsolete) {
+ RunTestOnIOThread(&AppCacheStorageImplTest::MakeGroupObsolete);
+}
+
+TEST_F(AppCacheStorageImplTest, MarkEntryAsForeign) {
+ RunTestOnIOThread(&AppCacheStorageImplTest::MarkEntryAsForeign);
+}
+
+TEST_F(AppCacheStorageImplTest, MarkEntryAsForeignWithLoadInProgress) {
+ RunTestOnIOThread(
+ &AppCacheStorageImplTest::MarkEntryAsForeignWithLoadInProgress);
+}
+
+TEST_F(AppCacheStorageImplTest, FindNoMainResponse) {
+ RunTestOnIOThread(&AppCacheStorageImplTest::FindNoMainResponse);
+}
+
+TEST_F(AppCacheStorageImplTest, BasicFindMainResponseInDatabase) {
+ RunTestOnIOThread(
+ &AppCacheStorageImplTest::BasicFindMainResponseInDatabase);
+}
+
+TEST_F(AppCacheStorageImplTest, BasicFindMainResponseInWorkingSet) {
+ RunTestOnIOThread(
+ &AppCacheStorageImplTest::BasicFindMainResponseInWorkingSet);
+}
+
+TEST_F(AppCacheStorageImplTest, BasicFindMainFallbackResponseInDatabase) {
+ RunTestOnIOThread(
+ &AppCacheStorageImplTest::BasicFindMainFallbackResponseInDatabase);
+}
+
+TEST_F(AppCacheStorageImplTest, BasicFindMainFallbackResponseInWorkingSet) {
+ RunTestOnIOThread(
+ &AppCacheStorageImplTest::BasicFindMainFallbackResponseInWorkingSet);
+}
+
+TEST_F(AppCacheStorageImplTest, BasicFindMainInterceptResponseInDatabase) {
+ RunTestOnIOThread(
+ &AppCacheStorageImplTest::BasicFindMainInterceptResponseInDatabase);
+}
+
+TEST_F(AppCacheStorageImplTest, BasicFindMainInterceptResponseInWorkingSet) {
+ RunTestOnIOThread(
+ &AppCacheStorageImplTest::BasicFindMainInterceptResponseInWorkingSet);
+}
+
+TEST_F(AppCacheStorageImplTest, FindMainResponseWithMultipleHits) {
+ RunTestOnIOThread(
+ &AppCacheStorageImplTest::FindMainResponseWithMultipleHits);
+}
+
+TEST_F(AppCacheStorageImplTest, FindMainResponseExclusionsInDatabase) {
+ RunTestOnIOThread(
+ &AppCacheStorageImplTest::FindMainResponseExclusionsInDatabase);
+}
+
+TEST_F(AppCacheStorageImplTest, FindMainResponseExclusionsInWorkingSet) {
+ RunTestOnIOThread(
+ &AppCacheStorageImplTest::FindMainResponseExclusionsInWorkingSet);
+}
+
+TEST_F(AppCacheStorageImplTest, FindInterceptPatternMatchInWorkingSet) {
+ RunTestOnIOThread(
+ &AppCacheStorageImplTest::FindInterceptPatternMatchInWorkingSet);
+}
+
+TEST_F(AppCacheStorageImplTest, FindInterceptPatternMatchInDatabase) {
+ RunTestOnIOThread(
+ &AppCacheStorageImplTest::FindInterceptPatternMatchInDatabase);
+}
+
+TEST_F(AppCacheStorageImplTest, FindFallbackPatternMatchInWorkingSet) {
+ RunTestOnIOThread(
+ &AppCacheStorageImplTest::FindFallbackPatternMatchInWorkingSet);
+}
+
+TEST_F(AppCacheStorageImplTest, FindFallbackPatternMatchInDatabase) {
+ RunTestOnIOThread(
+ &AppCacheStorageImplTest::FindFallbackPatternMatchInDatabase);
+}
+
+TEST_F(AppCacheStorageImplTest, Reinitialize1) {
+ RunTestOnIOThread(&AppCacheStorageImplTest::Reinitialize1);
+}
+
+TEST_F(AppCacheStorageImplTest, Reinitialize2) {
+ RunTestOnIOThread(&AppCacheStorageImplTest::Reinitialize2);
+}
+
+TEST_F(AppCacheStorageImplTest, Reinitialize3) {
+ RunTestOnIOThread(&AppCacheStorageImplTest::Reinitialize3);
+}
+
+// That's all folks!
+
+} // namespace appcache
diff --git a/content/browser/loader/cross_site_resource_handler.cc b/content/browser/loader/cross_site_resource_handler.cc
index 344d93e..8e56397 100644
--- a/content/browser/loader/cross_site_resource_handler.cc
+++ b/content/browser/loader/cross_site_resource_handler.cc
@@ -9,6 +9,7 @@
#include "base/bind.h"
#include "base/command_line.h"
#include "base/logging.h"
+#include "content/browser/appcache/appcache_interceptor.h"
#include "content/browser/child_process_security_policy_impl.h"
#include "content/browser/cross_site_request_manager.h"
#include "content/browser/frame_host/cross_site_transferring_request.h"
@@ -25,7 +26,6 @@
#include "content/public/common/url_constants.h"
#include "net/http/http_response_headers.h"
#include "net/url_request/url_request.h"
-#include "webkit/browser/appcache/appcache_interceptor.h"
namespace content {
@@ -308,7 +308,7 @@ void CrossSiteResourceHandler::StartCrossSiteTransition(
transfer_url_chain = request()->url_chain();
referrer = Referrer(GURL(request()->referrer()), info->GetReferrerPolicy());
- appcache::AppCacheInterceptor::PrepareForCrossSiteTransfer(
+ AppCacheInterceptor::PrepareForCrossSiteTransfer(
request(), global_id.child_id);
ResourceDispatcherHostImpl::Get()->MarkAsTransferredNavigation(global_id);
}
diff --git a/content/browser/loader/resource_dispatcher_host_impl.cc b/content/browser/loader/resource_dispatcher_host_impl.cc
index 9234315..61fc35b 100644
--- a/content/browser/loader/resource_dispatcher_host_impl.cc
+++ b/content/browser/loader/resource_dispatcher_host_impl.cc
@@ -23,6 +23,7 @@
#include "base/metrics/sparse_histogram.h"
#include "base/stl_util.h"
#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+#include "content/browser/appcache/appcache_interceptor.h"
#include "content/browser/appcache/chrome_appcache_service.h"
#include "content/browser/cert_store_impl.h"
#include "content/browser/child_process_security_policy_impl.h"
@@ -87,7 +88,6 @@
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_job_factory.h"
-#include "webkit/browser/appcache/appcache_interceptor.h"
#include "webkit/common/blob/blob_data.h"
#include "webkit/browser/blob/blob_data_handle.h"
#include "webkit/browser/blob/blob_storage_context.h"
@@ -797,7 +797,7 @@ void ResourceDispatcherHostImpl::DidFinishLoading(ResourceLoader* loader) {
void ResourceDispatcherHostImpl::OnInit() {
scheduler_.reset(new ResourceScheduler);
- appcache::AppCacheInterceptor::EnsureRegistered();
+ AppCacheInterceptor::EnsureRegistered();
}
void ResourceDispatcherHostImpl::OnShutdown() {
@@ -958,7 +958,7 @@ void ResourceDispatcherHostImpl::UpdateRequestForTransfer(
}
}
- appcache::AppCacheInterceptor::CompleteCrossSiteTransfer(
+ AppCacheInterceptor::CompleteCrossSiteTransfer(
loader->request(),
child_id,
request_data.appcache_host_id);
@@ -1137,7 +1137,7 @@ void ResourceDispatcherHostImpl::BeginRequest(
request_data.resource_type);
// Have the appcache associate its extra info with the request.
- appcache::AppCacheInterceptor::SetExtraRequestInfo(
+ AppCacheInterceptor::SetExtraRequestInfo(
new_request.get(), filter_->appcache_service(), child_id,
request_data.appcache_host_id, request_data.resource_type);
diff --git a/content/browser/loader/resource_loader.cc b/content/browser/loader/resource_loader.cc
index 02e9a1c..6bab366 100644
--- a/content/browser/loader/resource_loader.cc
+++ b/content/browser/loader/resource_loader.cc
@@ -8,6 +8,7 @@
#include "base/message_loop/message_loop.h"
#include "base/metrics/histogram.h"
#include "base/time/time.h"
+#include "content/browser/appcache/appcache_interceptor.h"
#include "content/browser/child_process_security_policy_impl.h"
#include "content/browser/loader/cross_site_resource_handler.h"
#include "content/browser/loader/detachable_resource_handler.h"
@@ -29,7 +30,6 @@
#include "net/http/http_response_headers.h"
#include "net/ssl/client_cert_store.h"
#include "net/url_request/url_request_status.h"
-#include "webkit/browser/appcache/appcache_interceptor.h"
using base::TimeDelta;
using base::TimeTicks;
@@ -54,7 +54,7 @@ void PopulateResourceResponse(net::URLRequest* request,
response->head.connection_info = response_info.connection_info;
response->head.was_fetched_via_proxy = request->was_fetched_via_proxy();
response->head.socket_address = request->GetSocketAddress();
- appcache::AppCacheInterceptor::GetExtraResponseInfo(
+ AppCacheInterceptor::GetExtraResponseInfo(
request,
&response->head.appcache_id,
&response->head.appcache_manifest_url);
diff --git a/content/content_browser.gypi b/content/content_browser.gypi
index 2785b7c..7286960 100644
--- a/content/content_browser.gypi
+++ b/content/content_browser.gypi
@@ -308,6 +308,8 @@
'browser/appcache/appcache_dispatcher_host.h',
'browser/appcache/appcache_frontend_proxy.cc',
'browser/appcache/appcache_frontend_proxy.h',
+ 'browser/appcache/appcache_interceptor.cc',
+ 'browser/appcache/appcache_interceptor.h',
'browser/appcache/chrome_appcache_service.cc',
'browser/appcache/chrome_appcache_service.h',
'browser/appcache/view_appcache_internals_job.h',
diff --git a/content/content_tests.gypi b/content/content_tests.gypi
index e1fe546..37a5463 100644
--- a/content/content_tests.gypi
+++ b/content/content_tests.gypi
@@ -333,6 +333,7 @@
'browser/accessibility/browser_accessibility_mac_unittest.mm',
'browser/accessibility/browser_accessibility_manager_unittest.cc',
'browser/accessibility/browser_accessibility_win_unittest.cc',
+ 'browser/appcache/appcache_storage_impl_unittest.cc',
'browser/appcache/chrome_appcache_service_unittest.cc',
'browser/browser_thread_unittest.cc',
'browser/browser_url_handler_impl_unittest.cc',
@@ -599,7 +600,6 @@
'../webkit/browser/appcache/appcache_request_handler_unittest.cc',
'../webkit/browser/appcache/appcache_response_unittest.cc',
'../webkit/browser/appcache/appcache_service_unittest.cc',
- '../webkit/browser/appcache/appcache_storage_impl_unittest.cc',
'../webkit/browser/appcache/appcache_storage_unittest.cc',
'../webkit/browser/appcache/appcache_unittest.cc',
'../webkit/browser/appcache/appcache_update_job_unittest.cc',