Commit f1651c4a authored by michaeln@chromium.org's avatar michaeln@chromium.org

Store the service worker script and its imports on first load, read them on...

Store the service worker script and its imports on first load, read them on subsequent loads. The list of resource ids is stored with registration data. As registrations are deleted the old resources are also deleted.

BUG=364247,364318

Review URL: https://codereview.chromium.org/293483002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@272418 0039d316-1c4b-4281-b951-d872f2087c98
parent 130f11a9
...@@ -412,7 +412,8 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::ReadRegistration( ...@@ -412,7 +412,8 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::ReadRegistration(
ServiceWorkerDatabase::Status ServiceWorkerDatabase::WriteRegistration( ServiceWorkerDatabase::Status ServiceWorkerDatabase::WriteRegistration(
const RegistrationData& registration, const RegistrationData& registration,
const std::vector<ResourceRecord>& resources) { const std::vector<ResourceRecord>& resources,
std::vector<int64>* newly_purgeable_resources) {
DCHECK(sequence_checker_.CalledOnValidSequencedThread()); DCHECK(sequence_checker_.CalledOnValidSequencedThread());
Status status = LazyOpen(true); Status status = LazyOpen(true);
if (status != STATUS_OK) if (status != STATUS_OK)
...@@ -441,7 +442,8 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::WriteRegistration( ...@@ -441,7 +442,8 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::WriteRegistration(
// suppported, so resource ids should not be overlapped between // suppported, so resource ids should not be overlapped between
// |registration| and |old_registration|. // |registration| and |old_registration|.
// TODO(nhiroki): Add DCHECK to make sure the overlap does not exist. // TODO(nhiroki): Add DCHECK to make sure the overlap does not exist.
status = DeleteResourceRecords(old_registration.version_id, &batch); status = DeleteResourceRecords(
old_registration.version_id, newly_purgeable_resources, &batch);
if (status != STATUS_OK) if (status != STATUS_OK)
return status; return status;
} }
...@@ -519,7 +521,8 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::UpdateLastCheckTime( ...@@ -519,7 +521,8 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::UpdateLastCheckTime(
ServiceWorkerDatabase::Status ServiceWorkerDatabase::DeleteRegistration( ServiceWorkerDatabase::Status ServiceWorkerDatabase::DeleteRegistration(
int64 registration_id, int64 registration_id,
const GURL& origin) { const GURL& origin,
std::vector<int64>* newly_purgeable_resources) {
DCHECK(sequence_checker_.CalledOnValidSequencedThread()); DCHECK(sequence_checker_.CalledOnValidSequencedThread());
Status status = LazyOpen(false); Status status = LazyOpen(false);
if (IsNewOrNonexistentDatabase(status)) if (IsNewOrNonexistentDatabase(status))
...@@ -551,7 +554,8 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::DeleteRegistration( ...@@ -551,7 +554,8 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::DeleteRegistration(
for (std::vector<RegistrationData>::const_iterator itr = for (std::vector<RegistrationData>::const_iterator itr =
registrations.begin(); itr != registrations.end(); ++itr) { registrations.begin(); itr != registrations.end(); ++itr) {
if (itr->registration_id == registration_id) { if (itr->registration_id == registration_id) {
status = DeleteResourceRecords(itr->version_id, &batch); status = DeleteResourceRecords(
itr->version_id, newly_purgeable_resources, &batch);
if (status != STATUS_OK) if (status != STATUS_OK)
return status; return status;
break; break;
...@@ -592,7 +596,8 @@ ServiceWorkerDatabase::ClearPurgeableResourceIds(const std::set<int64>& ids) { ...@@ -592,7 +596,8 @@ ServiceWorkerDatabase::ClearPurgeableResourceIds(const std::set<int64>& ids) {
} }
ServiceWorkerDatabase::Status ServiceWorkerDatabase::DeleteAllDataForOrigin( ServiceWorkerDatabase::Status ServiceWorkerDatabase::DeleteAllDataForOrigin(
const GURL& origin) { const GURL& origin,
std::vector<int64>* newly_purgeable_resources) {
DCHECK(sequence_checker_.CalledOnValidSequencedThread()); DCHECK(sequence_checker_.CalledOnValidSequencedThread());
Status status = LazyOpen(false); Status status = LazyOpen(false);
if (IsNewOrNonexistentDatabase(status)) if (IsNewOrNonexistentDatabase(status))
...@@ -616,7 +621,8 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::DeleteAllDataForOrigin( ...@@ -616,7 +621,8 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::DeleteAllDataForOrigin(
for (std::vector<RegistrationData>::const_iterator itr = for (std::vector<RegistrationData>::const_iterator itr =
registrations.begin(); itr != registrations.end(); ++itr) { registrations.begin(); itr != registrations.end(); ++itr) {
batch.Delete(CreateRegistrationKey(itr->registration_id, origin)); batch.Delete(CreateRegistrationKey(itr->registration_id, origin));
status = DeleteResourceRecords(itr->version_id, &batch); status = DeleteResourceRecords(
itr->version_id, newly_purgeable_resources, &batch);
if (status != STATUS_OK) if (status != STATUS_OK)
return status; return status;
} }
...@@ -768,6 +774,7 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::ReadResourceRecords( ...@@ -768,6 +774,7 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::ReadResourceRecords(
ServiceWorkerDatabase::Status ServiceWorkerDatabase::DeleteResourceRecords( ServiceWorkerDatabase::Status ServiceWorkerDatabase::DeleteResourceRecords(
int64 version_id, int64 version_id,
std::vector<int64>* newly_purgeable_resources,
leveldb::WriteBatch* batch) { leveldb::WriteBatch* batch) {
DCHECK(batch); DCHECK(batch);
...@@ -796,6 +803,7 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::DeleteResourceRecords( ...@@ -796,6 +803,7 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::DeleteResourceRecords(
// Currently resource sharing across versions and registrations is not // Currently resource sharing across versions and registrations is not
// supported, so we can purge this without caring about it. // supported, so we can purge this without caring about it.
PutPurgeableResourceIdToBatch(resource_id, batch); PutPurgeableResourceIdToBatch(resource_id, batch);
newly_purgeable_resources->push_back(resource_id);
} }
return STATUS_OK; return STATUS_OK;
} }
......
...@@ -67,6 +67,9 @@ class CONTENT_EXPORT ServiceWorkerDatabase { ...@@ -67,6 +67,9 @@ class CONTENT_EXPORT ServiceWorkerDatabase {
struct ResourceRecord { struct ResourceRecord {
int64 resource_id; int64 resource_id;
GURL url; GURL url;
ResourceRecord() {}
ResourceRecord(int64 id, GURL url) : resource_id(id), url(url) {}
}; };
// Reads next available ids from the database. Returns OK if they are // Reads next available ids from the database. Returns OK if they are
...@@ -114,7 +117,8 @@ class CONTENT_EXPORT ServiceWorkerDatabase { ...@@ -114,7 +117,8 @@ class CONTENT_EXPORT ServiceWorkerDatabase {
// Returns OK they are successfully written. Otherwise, returns an error. // Returns OK they are successfully written. Otherwise, returns an error.
Status WriteRegistration( Status WriteRegistration(
const RegistrationData& registration, const RegistrationData& registration,
const std::vector<ResourceRecord>& resources); const std::vector<ResourceRecord>& resources,
std::vector<int64>* newly_purgeable_resources);
// Updates a registration for |registration_id| to an active state. Returns OK // Updates a registration for |registration_id| to an active state. Returns OK
// if it's successfully updated. Otherwise, returns an error. // if it's successfully updated. Otherwise, returns an error.
...@@ -134,7 +138,8 @@ class CONTENT_EXPORT ServiceWorkerDatabase { ...@@ -134,7 +138,8 @@ class CONTENT_EXPORT ServiceWorkerDatabase {
// deleted or not found in the database. Otherwise, returns an error. // deleted or not found in the database. Otherwise, returns an error.
Status DeleteRegistration( Status DeleteRegistration(
int64 registration_id, int64 registration_id,
const GURL& origin); const GURL& origin,
std::vector<int64>* newly_purgeable_resources);
// As new resources are put into the diskcache, they go into an uncommitted // As new resources are put into the diskcache, they go into an uncommitted
// list. When a registration is saved that refers to those ids, they're // list. When a registration is saved that refers to those ids, they're
...@@ -171,7 +176,9 @@ class CONTENT_EXPORT ServiceWorkerDatabase { ...@@ -171,7 +176,9 @@ class CONTENT_EXPORT ServiceWorkerDatabase {
// resource records. Resources are moved to the purgeable list. Returns OK if // resource records. Resources are moved to the purgeable list. Returns OK if
// they are successfully deleted or not found in the database. Otherwise, // they are successfully deleted or not found in the database. Otherwise,
// returns an error. // returns an error.
Status DeleteAllDataForOrigin(const GURL& origin); Status DeleteAllDataForOrigin(
const GURL& origin,
std::vector<int64>* newly_purgeable_resources);
bool is_disabled() const { return is_disabled_; } bool is_disabled() const { return is_disabled_; }
bool was_corruption_detected() const { return was_corruption_detected_; } bool was_corruption_detected() const { return was_corruption_detected_; }
...@@ -214,6 +221,7 @@ class CONTENT_EXPORT ServiceWorkerDatabase { ...@@ -214,6 +221,7 @@ class CONTENT_EXPORT ServiceWorkerDatabase {
// returns an error. // returns an error.
Status DeleteResourceRecords( Status DeleteResourceRecords(
int64 version_id, int64 version_id,
std::vector<int64>* newly_purgeable_resources,
leveldb::WriteBatch* batch); leveldb::WriteBatch* batch);
// Reads resource ids for |id_key_prefix| from the database. Returns OK if // Reads resource ids for |id_key_prefix| from the database. Returns OK if
......
...@@ -16,11 +16,11 @@ namespace content { ...@@ -16,11 +16,11 @@ namespace content {
// TODO(michaeln): If this reuse sticks, refactor/move the // TODO(michaeln): If this reuse sticks, refactor/move the
// resused classes to a more common location. // resused classes to a more common location.
class ServiceWorkerDiskCache class CONTENT_EXPORT ServiceWorkerDiskCache
: public appcache::AppCacheDiskCache { : public appcache::AppCacheDiskCache {
}; };
class ServiceWorkerResponseReader class CONTENT_EXPORT ServiceWorkerResponseReader
: public appcache::AppCacheResponseReader { : public appcache::AppCacheResponseReader {
protected: protected:
// Should only be constructed by the storage class. // Should only be constructed by the storage class.
...@@ -30,7 +30,7 @@ class ServiceWorkerResponseReader ...@@ -30,7 +30,7 @@ class ServiceWorkerResponseReader
ServiceWorkerDiskCache* disk_cache); ServiceWorkerDiskCache* disk_cache);
}; };
class ServiceWorkerResponseWriter class CONTENT_EXPORT ServiceWorkerResponseWriter
: public appcache::AppCacheResponseWriter { : public appcache::AppCacheResponseWriter {
protected: protected:
// Should only be constructed by the storage class. // Should only be constructed by the storage class.
...@@ -40,7 +40,7 @@ class ServiceWorkerResponseWriter ...@@ -40,7 +40,7 @@ class ServiceWorkerResponseWriter
ServiceWorkerDiskCache* disk_cache); ServiceWorkerDiskCache* disk_cache);
}; };
struct HttpResponseInfoIOBuffer struct CONTENT_EXPORT HttpResponseInfoIOBuffer
: public appcache::HttpResponseInfoIOBuffer { : public appcache::HttpResponseInfoIOBuffer {
public: public:
HttpResponseInfoIOBuffer() : appcache::HttpResponseInfoIOBuffer() {} HttpResponseInfoIOBuffer() : appcache::HttpResponseInfoIOBuffer() {}
......
...@@ -89,7 +89,6 @@ void ServiceWorkerRegisterJob::set_registration( ...@@ -89,7 +89,6 @@ void ServiceWorkerRegisterJob::set_registration(
ServiceWorkerRegistration* ServiceWorkerRegisterJob::registration() { ServiceWorkerRegistration* ServiceWorkerRegisterJob::registration() {
DCHECK(phase_ >= REGISTER) << phase_; DCHECK(phase_ >= REGISTER) << phase_;
DCHECK(internal_.registration);
return internal_.registration; return internal_.registration;
} }
......
...@@ -50,8 +50,8 @@ void ServiceWorkerScriptCacheMap::GetResources( ...@@ -50,8 +50,8 @@ void ServiceWorkerScriptCacheMap::GetResources(
DCHECK(resources->empty()); DCHECK(resources->empty());
for (ResourceIDMap::const_iterator it = resource_ids_.begin(); for (ResourceIDMap::const_iterator it = resource_ids_.begin();
it != resource_ids_.end(); ++it) { it != resource_ids_.end(); ++it) {
ServiceWorkerDatabase::ResourceRecord record = { it->second, it->first }; resources->push_back(
resources->push_back(record); ServiceWorkerDatabase::ResourceRecord(it->second, it->first));
} }
} }
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#ifndef CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_STORAGE_H_ #ifndef CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_STORAGE_H_
#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_STORAGE_H_ #define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_STORAGE_H_
#include <deque>
#include <map> #include <map>
#include <set> #include <set>
#include <vector> #include <vector>
...@@ -53,16 +54,6 @@ class CONTENT_EXPORT ServiceWorkerStorage { ...@@ -53,16 +54,6 @@ class CONTENT_EXPORT ServiceWorkerStorage {
void(ServiceWorkerStatusCode status, int result)> void(ServiceWorkerStatusCode status, int result)>
CompareCallback; CompareCallback;
struct InitialData {
int64 next_registration_id;
int64 next_version_id;
int64 next_resource_id;
std::set<GURL> origins;
InitialData();
~InitialData();
};
ServiceWorkerStorage(const base::FilePath& path, ServiceWorkerStorage(const base::FilePath& path,
base::WeakPtr<ServiceWorkerContextCore> context, base::WeakPtr<ServiceWorkerContextCore> context,
base::SequencedTaskRunner* database_task_runner, base::SequencedTaskRunner* database_task_runner,
...@@ -130,37 +121,72 @@ class CONTENT_EXPORT ServiceWorkerStorage { ...@@ -130,37 +121,72 @@ class CONTENT_EXPORT ServiceWorkerStorage {
private: private:
friend class ServiceWorkerStorageTest; friend class ServiceWorkerStorageTest;
FRIEND_TEST_ALL_PREFIXES(ServiceWorkerStorageTest,
ResourceIdsAreStoredAndPurged);
struct InitialData {
int64 next_registration_id;
int64 next_version_id;
int64 next_resource_id;
std::set<GURL> origins;
InitialData();
~InitialData();
};
typedef std::vector<ServiceWorkerDatabase::RegistrationData> RegistrationList; typedef std::vector<ServiceWorkerDatabase::RegistrationData> RegistrationList;
typedef std::vector<ServiceWorkerDatabase::ResourceRecord> ResourceList; typedef std::vector<ServiceWorkerDatabase::ResourceRecord> ResourceList;
typedef std::map<int64, scoped_refptr<ServiceWorkerRegistration> >
RegistrationRefsById;
typedef base::Callback<void(
InitialData* data,
ServiceWorkerDatabase::Status status)> InitializeCallback;
typedef base::Callback<void(
const GURL& origin,
const std::vector<int64>& newly_purgeable_resources,
ServiceWorkerDatabase::Status status)> WriteRegistrationCallback;
typedef base::Callback<void(
bool origin_is_deletable,
const std::vector<int64>& newly_purgeable_resources,
ServiceWorkerDatabase::Status status)> DeleteRegistrationCallback;
typedef base::Callback<void(
const ServiceWorkerDatabase::RegistrationData& data,
const ResourceList& resources,
ServiceWorkerDatabase::Status status)> FindInDBCallback;
base::FilePath GetDatabasePath();
base::FilePath GetDiskCachePath();
bool LazyInitialize( bool LazyInitialize(
const base::Closure& callback); const base::Closure& callback);
void DidReadInitialData( void DidReadInitialData(
InitialData* data, InitialData* data,
ServiceWorkerDatabase::Status status); ServiceWorkerDatabase::Status status);
void DidGetRegistrationsForPattern( void DidFindRegistrationForDocument(
const GURL& scope, const GURL& document_url,
const FindRegistrationCallback& callback, const FindRegistrationCallback& callback,
RegistrationList* registrations, const ServiceWorkerDatabase::RegistrationData& data,
const ResourceList& resources,
ServiceWorkerDatabase::Status status); ServiceWorkerDatabase::Status status);
void DidGetRegistrationsForDocument( void DidFindRegistrationForPattern(
const GURL& scope, const GURL& scope,
const FindRegistrationCallback& callback, const FindRegistrationCallback& callback,
RegistrationList* registrations, const ServiceWorkerDatabase::RegistrationData& data,
const ResourceList& resources,
ServiceWorkerDatabase::Status status); ServiceWorkerDatabase::Status status);
void DidReadRegistrationForId( void DidFindRegistrationForId(
const FindRegistrationCallback& callback, const FindRegistrationCallback& callback,
ServiceWorkerDatabase::RegistrationData* registration, const ServiceWorkerDatabase::RegistrationData& data,
ResourceList* resources, const ResourceList& resources,
ServiceWorkerDatabase::Status status); ServiceWorkerDatabase::Status status);
void DidGetAllRegistrations( void DidGetAllRegistrations(
const GetAllRegistrationInfosCallback& callback, const GetAllRegistrationInfosCallback& callback,
RegistrationList* registrations, RegistrationList* registrations,
ServiceWorkerDatabase::Status status); ServiceWorkerDatabase::Status status);
void DidStoreRegistration( void DidStoreRegistration(
const GURL& origin,
const StatusCallback& callback, const StatusCallback& callback,
const GURL& origin,
const std::vector<int64>& newly_purgeable_resources,
ServiceWorkerDatabase::Status status); ServiceWorkerDatabase::Status status);
void DidUpdateToActiveState( void DidUpdateToActiveState(
const StatusCallback& callback, const StatusCallback& callback,
...@@ -169,10 +195,12 @@ class CONTENT_EXPORT ServiceWorkerStorage { ...@@ -169,10 +195,12 @@ class CONTENT_EXPORT ServiceWorkerStorage {
const GURL& origin, const GURL& origin,
const StatusCallback& callback, const StatusCallback& callback,
bool origin_is_deletable, bool origin_is_deletable,
const std::vector<int64>& newly_purgeable_resources,
ServiceWorkerDatabase::Status status); ServiceWorkerDatabase::Status status);
scoped_refptr<ServiceWorkerRegistration> CreateRegistration( scoped_refptr<ServiceWorkerRegistration> GetOrCreateRegistration(
const ServiceWorkerDatabase::RegistrationData& data); const ServiceWorkerDatabase::RegistrationData& data,
const ResourceList& resources);
ServiceWorkerRegistration* FindInstallingRegistrationForDocument( ServiceWorkerRegistration* FindInstallingRegistrationForDocument(
const GURL& document_url); const GURL& document_url);
ServiceWorkerRegistration* FindInstallingRegistrationForPattern( ServiceWorkerRegistration* FindInstallingRegistrationForPattern(
...@@ -180,13 +208,50 @@ class CONTENT_EXPORT ServiceWorkerStorage { ...@@ -180,13 +208,50 @@ class CONTENT_EXPORT ServiceWorkerStorage {
ServiceWorkerRegistration* FindInstallingRegistrationForId( ServiceWorkerRegistration* FindInstallingRegistrationForId(
int64 registration_id); int64 registration_id);
// For finding registrations being installed.
typedef std::map<int64, scoped_refptr<ServiceWorkerRegistration> >
RegistrationRefsById;
RegistrationRefsById installing_registrations_;
// Lazy disk_cache getter. // Lazy disk_cache getter.
ServiceWorkerDiskCache* disk_cache(); ServiceWorkerDiskCache* disk_cache();
void OnDiskCacheInitialized(int rv);
void StartPurgingResources(const std::vector<int64>& ids);
void PurgeResource(int64 id);
void OnResourcePurged(int64 id, int rv);
// Static cross-thread helpers.
static void ReadInitialDataFromDB(
ServiceWorkerDatabase* database,
scoped_refptr<base::SequencedTaskRunner> original_task_runner,
const InitializeCallback& callback);
static void DeleteRegistrationFromDB(
ServiceWorkerDatabase* database,
scoped_refptr<base::SequencedTaskRunner> original_task_runner,
int64 registration_id,
const GURL& origin,
const DeleteRegistrationCallback& callback);
static void WriteRegistrationInDB(
ServiceWorkerDatabase* database,
scoped_refptr<base::SequencedTaskRunner> original_task_runner,
const ServiceWorkerDatabase::RegistrationData& registration,
const ResourceList& resources,
const WriteRegistrationCallback& callback);
static void FindForDocumentInDB(
ServiceWorkerDatabase* database,
scoped_refptr<base::SequencedTaskRunner> original_task_runner,
const GURL& document_url,
const FindInDBCallback& callback);
static void FindForPatternInDB(
ServiceWorkerDatabase* database,
scoped_refptr<base::SequencedTaskRunner> original_task_runner,
const GURL& scope,
const FindInDBCallback& callback);
static void FindForIdInDB(
ServiceWorkerDatabase* database,
scoped_refptr<base::SequencedTaskRunner> original_task_runner,
int64 registration_id,
const GURL& origin,
const FindInDBCallback& callback);
// For finding registrations being installed.
RegistrationRefsById installing_registrations_;
// Origins having registations. // Origins having registations.
std::set<GURL> registered_origins_; std::set<GURL> registered_origins_;
...@@ -216,6 +281,8 @@ class CONTENT_EXPORT ServiceWorkerStorage { ...@@ -216,6 +281,8 @@ class CONTENT_EXPORT ServiceWorkerStorage {
scoped_refptr<base::MessageLoopProxy> disk_cache_thread_; scoped_refptr<base::MessageLoopProxy> disk_cache_thread_;
scoped_refptr<quota::QuotaManagerProxy> quota_manager_proxy_; scoped_refptr<quota::QuotaManagerProxy> quota_manager_proxy_;
scoped_ptr<ServiceWorkerDiskCache> disk_cache_; scoped_ptr<ServiceWorkerDiskCache> disk_cache_;
std::deque<int64> purgeable_reource_ids_;
bool is_purge_pending_;
base::WeakPtrFactory<ServiceWorkerStorage> weak_factory_; base::WeakPtrFactory<ServiceWorkerStorage> weak_factory_;
......
...@@ -2,22 +2,32 @@ ...@@ -2,22 +2,32 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "content/browser/service_worker/service_worker_storage.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/message_loop/message_loop.h" #include "base/message_loop/message_loop.h"
#include "base/run_loop.h" #include "base/run_loop.h"
#include "content/browser/browser_thread_impl.h" #include "content/browser/browser_thread_impl.h"
#include "content/browser/service_worker/service_worker_context_core.h" #include "content/browser/service_worker/service_worker_context_core.h"
#include "content/browser/service_worker/service_worker_disk_cache.h"
#include "content/browser/service_worker/service_worker_registration.h" #include "content/browser/service_worker/service_worker_registration.h"
#include "content/browser/service_worker/service_worker_storage.h"
#include "content/browser/service_worker/service_worker_version.h" #include "content/browser/service_worker/service_worker_version.h"
#include "content/common/service_worker/service_worker_status_code.h"
#include "content/public/test/test_browser_thread_bundle.h" #include "content/public/test/test_browser_thread_bundle.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/http/http_response_headers.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
using net::IOBuffer;
using net::WrappedIOBuffer;
namespace content { namespace content {
namespace { namespace {
typedef ServiceWorkerDatabase::RegistrationData RegistrationData;
typedef ServiceWorkerDatabase::ResourceRecord ResourceRecord;
void StatusCallback(bool* was_called, void StatusCallback(bool* was_called,
ServiceWorkerStatusCode* result, ServiceWorkerStatusCode* result,
ServiceWorkerStatusCode status) { ServiceWorkerStatusCode status) {
...@@ -63,6 +73,74 @@ ServiceWorkerStorage::GetAllRegistrationInfosCallback MakeGetAllCallback( ...@@ -63,6 +73,74 @@ ServiceWorkerStorage::GetAllRegistrationInfosCallback MakeGetAllCallback(
return base::Bind(&GetAllCallback, was_called, all); return base::Bind(&GetAllCallback, was_called, all);
} }
void OnIOComplete(int* rv_out, int rv) {
*rv_out = rv;
}
void WriteBasicResponse(ServiceWorkerStorage* storage, int64 id) {
scoped_ptr<ServiceWorkerResponseWriter> writer =
storage->CreateResponseWriter(id);
const char kHttpHeaders[] =
"HTTP/1.0 200 HONKYDORY\0Content-Length: 6\0\0";
const char kHttpBody[] = "Hello\0";
scoped_refptr<IOBuffer> body(new WrappedIOBuffer(kHttpBody));
std::string raw_headers(kHttpHeaders, arraysize(kHttpHeaders));
scoped_ptr<net::HttpResponseInfo> info(new net::HttpResponseInfo);
info->request_time = base::Time::Now();
info->response_time = base::Time::Now();
info->was_cached = false;
info->headers = new net::HttpResponseHeaders(raw_headers);
scoped_refptr<HttpResponseInfoIOBuffer> info_buffer =
new HttpResponseInfoIOBuffer(info.release());
int rv = -1234;
writer->WriteInfo(info_buffer, base::Bind(&OnIOComplete, &rv));
base::RunLoop().RunUntilIdle();
EXPECT_LT(0, rv);
rv = -1234;
writer->WriteData(body, arraysize(kHttpBody),
base::Bind(&OnIOComplete, &rv));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(static_cast<int>(arraysize(kHttpBody)), rv);
}
bool VerifyBasicResponse(ServiceWorkerStorage* storage, int64 id,
bool expected_positive_result) {
const char kExpectedHttpBody[] = "Hello\0";
scoped_ptr<ServiceWorkerResponseReader> reader =
storage->CreateResponseReader(id);
scoped_refptr<HttpResponseInfoIOBuffer> info_buffer =
new HttpResponseInfoIOBuffer();
int rv = -1234;
reader->ReadInfo(info_buffer, base::Bind(&OnIOComplete, &rv));
base::RunLoop().RunUntilIdle();
if (expected_positive_result)
EXPECT_LT(0, rv);
if (rv <= 0)
return false;
const int kBigEnough = 512;
scoped_refptr<net::IOBuffer> buffer = new IOBuffer(kBigEnough);
rv = -1234;
reader->ReadData(buffer, kBigEnough, base::Bind(&OnIOComplete, &rv));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(static_cast<int>(arraysize(kExpectedHttpBody)), rv);
if (rv <= 0)
return false;
bool status_match =
std::string("HONKYDORY") ==
info_buffer->http_info->headers->GetStatusText();
bool data_match =
std::string(kExpectedHttpBody) == std::string(buffer->data());
EXPECT_TRUE(status_match);
EXPECT_TRUE(data_match);
return status_match && data_match;
}
} // namespace } // namespace
class ServiceWorkerStorageTest : public testing::Test { class ServiceWorkerStorageTest : public testing::Test {
...@@ -88,6 +166,19 @@ class ServiceWorkerStorageTest : public testing::Test { ...@@ -88,6 +166,19 @@ class ServiceWorkerStorageTest : public testing::Test {
ServiceWorkerStorage* storage() { return context_->storage(); } ServiceWorkerStorage* storage() { return context_->storage(); }
// A static class method for friendliness.
static void VerifyPurgeableListStatusCallback(
ServiceWorkerDatabase* database,
std::set<int64> *purgeable_ids,
bool* was_called,
ServiceWorkerStatusCode* result,
ServiceWorkerStatusCode status) {
*was_called = true;
*result = status;
EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
database->GetPurgeableResourceIds(purgeable_ids));
}
protected: protected:
scoped_ptr<ServiceWorkerContextCore> context_; scoped_ptr<ServiceWorkerContextCore> context_;
base::WeakPtr<ServiceWorkerContextCore> context_ptr_; base::WeakPtr<ServiceWorkerContextCore> context_ptr_;
...@@ -95,9 +186,9 @@ class ServiceWorkerStorageTest : public testing::Test { ...@@ -95,9 +186,9 @@ class ServiceWorkerStorageTest : public testing::Test {
}; };
TEST_F(ServiceWorkerStorageTest, StoreFindUpdateDeleteRegistration) { TEST_F(ServiceWorkerStorageTest, StoreFindUpdateDeleteRegistration) {
const GURL kScope("http://www.test.com/scope/*"); const GURL kScope("http://www.test.not/scope/*");
const GURL kScript("http://www.test.com/script.js"); const GURL kScript("http://www.test.not/script.js");
const GURL kDocumentUrl("http://www.test.com/scope/document.html"); const GURL kDocumentUrl("http://www.test.not/scope/document.html");
const int64 kRegistrationId = 0; const int64 kRegistrationId = 0;
const int64 kVersionId = 0; const int64 kVersionId = 0;
...@@ -310,9 +401,9 @@ TEST_F(ServiceWorkerStorageTest, StoreFindUpdateDeleteRegistration) { ...@@ -310,9 +401,9 @@ TEST_F(ServiceWorkerStorageTest, StoreFindUpdateDeleteRegistration) {
} }
TEST_F(ServiceWorkerStorageTest, InstallingRegistrationsAreFindable) { TEST_F(ServiceWorkerStorageTest, InstallingRegistrationsAreFindable) {
const GURL kScope("http://www.test.com/scope/*"); const GURL kScope("http://www.test.not/scope/*");
const GURL kScript("http://www.test.com/script.js"); const GURL kScript("http://www.test.not/script.js");
const GURL kDocumentUrl("http://www.test.com/scope/document.html"); const GURL kDocumentUrl("http://www.test.not/scope/document.html");
const int64 kRegistrationId = 0; const int64 kRegistrationId = 0;
const int64 kVersionId = 0; const int64 kVersionId = 0;
...@@ -442,4 +533,80 @@ TEST_F(ServiceWorkerStorageTest, InstallingRegistrationsAreFindable) { ...@@ -442,4 +533,80 @@ TEST_F(ServiceWorkerStorageTest, InstallingRegistrationsAreFindable) {
was_called = false; was_called = false;
} }
TEST_F(ServiceWorkerStorageTest, ResourceIdsAreStoredAndPurged) {
storage()->LazyInitialize(base::Bind(&base::DoNothing));
base::RunLoop().RunUntilIdle();
const GURL kScope("http://www.test.not/scope/*");
const GURL kScript("http://www.test.not/script.js");
const GURL kImport("http://www.test.not/import.js");
const GURL kDocumentUrl("http://www.test.not/scope/document.html");
const int64 kRegistrationId = storage()->NewRegistrationId();
const int64 kVersionId = storage()->NewVersionId();
const int64 kResourceId1 = storage()->NewResourceId();
const int64 kResourceId2 = storage()->NewResourceId();
// Cons up a new registration+version with two script resources.
RegistrationData data;
data.registration_id = kRegistrationId;
data.scope = kScope;
data.script = kScript;
data.version_id = kVersionId;
data.is_active = false;
std::vector<ResourceRecord> resources;
resources.push_back(ResourceRecord(kResourceId1, kScript));
resources.push_back(ResourceRecord(kResourceId2, kImport));
scoped_refptr<ServiceWorkerRegistration> registration =
storage()->GetOrCreateRegistration(data, resources);
registration->pending_version()->SetStatus(ServiceWorkerVersion::NEW);
// Add the resources ids to the uncommitted list.
std::set<int64> resource_ids;
resource_ids.insert(kResourceId1);
resource_ids.insert(kResourceId2);
EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
storage()->database_->WriteUncommittedResourceIds(resource_ids));
// And dump something in the disk cache for them.
WriteBasicResponse(storage(), kResourceId1);
WriteBasicResponse(storage(), kResourceId2);
EXPECT_TRUE(VerifyBasicResponse(storage(), kResourceId1, true));
EXPECT_TRUE(VerifyBasicResponse(storage(), kResourceId2, true));
// Storing the registration/version should take the resources ids out
// of the uncommitted list.
bool was_called = false;
ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED;
storage()->StoreRegistration(registration, registration->pending_version(),
MakeStatusCallback(&was_called, &result));
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(was_called);
EXPECT_EQ(SERVICE_WORKER_OK, result);
std::set<int64> verify_ids;
EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
storage()->database_->GetUncommittedResourceIds(&verify_ids));
EXPECT_TRUE(verify_ids.empty());
// Deleting it should result in the resources being added to the
// purgeable list and then doomed in the disk cache and removed from
// that list.
was_called = false;
verify_ids.clear();
storage()->DeleteRegistration(
registration->id(), kScope.GetOrigin(),
base::Bind(&VerifyPurgeableListStatusCallback,
base::Unretained(storage()->database_.get()),
&verify_ids, &was_called, &result));
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(was_called);
EXPECT_EQ(SERVICE_WORKER_OK, result);
EXPECT_EQ(2u, verify_ids.size());
verify_ids.clear();
EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
storage()->database_->GetPurgeableResourceIds(&verify_ids));
EXPECT_TRUE(verify_ids.empty());
EXPECT_FALSE(VerifyBasicResponse(storage(), kResourceId1, false));
EXPECT_FALSE(VerifyBasicResponse(storage(), kResourceId2, false));
}
} // namespace content } // namespace content
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment