Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(198)

Unified Diff: content/browser/service_worker/service_worker_write_to_cache_job_unittest.cc

Issue 1166433003: Service Worker: Don't write to disk during update until proven necessary (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: review comments Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « content/browser/service_worker/service_worker_write_to_cache_job.cc ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: content/browser/service_worker/service_worker_write_to_cache_job_unittest.cc
diff --git a/content/browser/service_worker/service_worker_write_to_cache_job_unittest.cc b/content/browser/service_worker/service_worker_write_to_cache_job_unittest.cc
index cd90d45f731150edf3217673b3d97d4d506b0dac..5fc56c4c48fbfd60703fa65fbc635784ab93fea8 100644
--- a/content/browser/service_worker/service_worker_write_to_cache_job_unittest.cc
+++ b/content/browser/service_worker/service_worker_write_to_cache_job_unittest.cc
@@ -7,12 +7,15 @@
#include "content/browser/service_worker/embedded_worker_test_helper.h"
#include "content/browser/service_worker/service_worker_context_core.h"
#include "content/browser/service_worker/service_worker_context_request_handler.h"
+#include "content/browser/service_worker/service_worker_disk_cache.h"
#include "content/browser/service_worker/service_worker_provider_host.h"
#include "content/browser/service_worker/service_worker_registration.h"
+#include "content/browser/service_worker/service_worker_test_utils.h"
#include "content/browser/service_worker/service_worker_utils.h"
#include "content/common/resource_request_body.h"
#include "content/public/test/mock_resource_context.h"
#include "content/public/test/test_browser_thread_bundle.h"
+#include "net/base/io_buffer.h"
#include "net/base/load_flags.h"
#include "net/http/http_response_headers.h"
#include "net/url_request/url_request_context.h"
@@ -26,8 +29,6 @@ namespace content {
namespace {
-int kMockRenderProcessId = 1224;
-int kMockProviderId = 1;
const char kHeaders[] =
"HTTP/1.1 200 OK\0"
"Content-Type: text/javascript\0"
@@ -38,6 +39,14 @@ const char kScriptCode[] = "// no script code\n";
void EmptyCallback() {
}
+// The blocksize that ServiceWorkerWriteToCacheJob reads/writes at a time.
+const int kBlockSize = 16 * 1024;
+const int kNumBlocks = 8;
+const int kMiddleBlock = 5;
+
+std::string GenerateLongResponse() {
+ return std::string(kNumBlocks * kBlockSize, 'a');
+}
net::URLRequestJob* CreateNormalURLRequestJob(
net::URLRequest* request,
net::NetworkDelegate* network_delegate) {
@@ -48,6 +57,14 @@ net::URLRequestJob* CreateNormalURLRequestJob(
true);
}
+net::URLRequestJob* CreateResponseJob(const std::string& response_data,
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate) {
+ return new net::URLRequestTestJob(request, network_delegate,
+ std::string(kHeaders, arraysize(kHeaders)),
+ response_data, true);
+}
+
net::URLRequestJob* CreateInvalidMimeTypeJob(
net::URLRequest* request,
net::NetworkDelegate* network_delegate) {
@@ -141,7 +158,7 @@ class MockHttpProtocolHandler
typedef base::Callback<
net::URLRequestJob*(net::URLRequest*, net::NetworkDelegate*)> JobCallback;
- MockHttpProtocolHandler(ResourceContext* resource_context)
+ explicit MockHttpProtocolHandler(ResourceContext* resource_context)
: resource_context_(resource_context) {}
~MockHttpProtocolHandler() override {}
@@ -164,7 +181,72 @@ class MockHttpProtocolHandler
ResourceContext* resource_context_;
JobCallback create_job_callback_;
};
-}
+
+class ResponseVerifier : public base::RefCounted<ResponseVerifier> {
+ public:
+ ResponseVerifier(scoped_ptr<ServiceWorkerResponseReader> reader,
+ const std::string& expected,
+ const base::Callback<void(bool)> callback)
+ : reader_(reader.release()), expected_(expected), callback_(callback) {}
+
+ void Start() {
+ info_buffer_ = new HttpResponseInfoIOBuffer();
+ io_buffer_ = new net::IOBuffer(kBlockSize);
+ reader_->ReadInfo(info_buffer_.get(),
+ base::Bind(&ResponseVerifier::OnReadInfoComplete, this));
+ bytes_read_ = 0;
+ }
+
+ void OnReadInfoComplete(int result) {
+ if (result < 0) {
+ callback_.Run(false);
+ return;
+ }
+ if (info_buffer_->response_data_size !=
+ static_cast<int>(expected_.size())) {
+ callback_.Run(false);
+ return;
+ }
+ ReadSomeData();
+ }
+
+ void ReadSomeData() {
+ reader_->ReadData(io_buffer_.get(), kBlockSize,
+ base::Bind(&ResponseVerifier::OnReadDataComplete, this));
+ }
+
+ void OnReadDataComplete(int result) {
+ if (result < 0) {
+ callback_.Run(false);
+ return;
+ }
+ if (result == 0) {
+ callback_.Run(true);
+ return;
+ }
+ std::string str(io_buffer_->data(), result);
+ std::string expect = expected_.substr(bytes_read_, result);
+ if (str != expect) {
+ callback_.Run(false);
+ return;
+ }
+ bytes_read_ += result;
+ ReadSomeData();
+ }
+
+ private:
+ friend class base::RefCounted<ResponseVerifier>;
+ ~ResponseVerifier() {}
+
+ scoped_ptr<ServiceWorkerResponseReader> reader_;
+ const std::string expected_;
+ base::Callback<void(bool)> callback_;
+ scoped_refptr<HttpResponseInfoIOBuffer> info_buffer_;
+ scoped_refptr<net::IOBuffer> io_buffer_;
+ size_t bytes_read_;
+};
+
+} // namespace
class ServiceWorkerWriteToCacheJobTest : public testing::Test {
public:
@@ -173,27 +255,24 @@ class ServiceWorkerWriteToCacheJobTest : public testing::Test {
mock_protocol_handler_(nullptr) {}
~ServiceWorkerWriteToCacheJobTest() override {}
- void SetUp() override {
- helper_.reset(
- new EmbeddedWorkerTestHelper(base::FilePath(), kMockRenderProcessId));
-
- // A new unstored registration/version.
- scope_ = GURL("https://host/scope/");
- script_url_ = GURL("https://host/script.js");
- registration_ =
- new ServiceWorkerRegistration(scope_, 1L, context()->AsWeakPtr());
- version_ = new ServiceWorkerVersion(
- registration_.get(), script_url_, 1L, context()->AsWeakPtr());
-
- // An empty host.
+ void CreateHostForVersion(
+ int process_id,
+ int provider_id,
+ const scoped_refptr<ServiceWorkerVersion>& version) {
scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
- kMockRenderProcessId, MSG_ROUTING_NONE, kMockProviderId,
- SERVICE_WORKER_PROVIDER_FOR_WINDOW, context()->AsWeakPtr(), nullptr));
- provider_host_ = host->AsWeakPtr();
+ process_id, MSG_ROUTING_NONE, provider_id,
+ SERVICE_WORKER_PROVIDER_FOR_WORKER, context()->AsWeakPtr(), nullptr));
+ base::WeakPtr<ServiceWorkerProviderHost> provider_host = host->AsWeakPtr();
context()->AddProviderHost(host.Pass());
- provider_host_->running_hosted_version_ = version_;
+ provider_host->running_hosted_version_ = version;
+ }
- context()->storage()->LazyInitialize(base::Bind(&EmptyCallback));
+ void SetUpScriptRequest(int process_id, int provider_id) {
+ request_.reset();
+ url_request_context_.reset();
+ url_request_job_factory_.reset();
+ mock_protocol_handler_ = nullptr;
+ // URLRequestJobs may post clean-up tasks on destruction.
base::RunLoop().RunUntilIdle();
url_request_context_.reset(new net::URLRequestContext);
@@ -206,20 +285,38 @@ class ServiceWorkerWriteToCacheJobTest : public testing::Test {
request_ = url_request_context_->CreateRequest(
script_url_, net::DEFAULT_PRIORITY, &url_request_delegate_);
ServiceWorkerRequestHandler::InitializeHandler(
- request_.get(),
- context_wrapper(),
- &blob_storage_context_,
- kMockRenderProcessId,
- kMockProviderId,
- false,
- FETCH_REQUEST_MODE_NO_CORS,
- FETCH_CREDENTIALS_MODE_OMIT,
- RESOURCE_TYPE_SERVICE_WORKER,
- REQUEST_CONTEXT_TYPE_SERVICE_WORKER,
- REQUEST_CONTEXT_FRAME_TYPE_NONE,
+ request_.get(), context_wrapper(), &blob_storage_context_, process_id,
+ provider_id, false, FETCH_REQUEST_MODE_NO_CORS,
+ FETCH_CREDENTIALS_MODE_OMIT, RESOURCE_TYPE_SERVICE_WORKER,
+ REQUEST_CONTEXT_TYPE_SERVICE_WORKER, REQUEST_CONTEXT_FRAME_TYPE_NONE,
scoped_refptr<ResourceRequestBody>());
}
+ int NextRenderProcessId() { return next_render_process_id_++; }
+ int NextProviderId() { return next_provider_id_++; }
+ int NextVersionId() { return next_version_id_++; }
+
+ void SetUp() override {
+ int render_process_id = NextRenderProcessId();
+ int provider_id = NextProviderId();
+ helper_.reset(
+ new EmbeddedWorkerTestHelper(base::FilePath(), render_process_id));
+
+ // A new unstored registration/version.
+ scope_ = GURL("https://host/scope/");
+ script_url_ = GURL("https://host/script.js");
+ registration_ =
+ new ServiceWorkerRegistration(scope_, 1L, context()->AsWeakPtr());
+ version_ =
+ new ServiceWorkerVersion(registration_.get(), script_url_,
+ NextVersionId(), context()->AsWeakPtr());
+ CreateHostForVersion(render_process_id, provider_id, version_);
+ SetUpScriptRequest(render_process_id, provider_id);
+
+ context()->storage()->LazyInitialize(base::Bind(&EmptyCallback));
+ base::RunLoop().RunUntilIdle();
+ }
+
void TearDown() override {
request_.reset();
url_request_context_.reset();
@@ -232,6 +329,63 @@ class ServiceWorkerWriteToCacheJobTest : public testing::Test {
base::RunLoop().RunUntilIdle();
}
+ int CreateIncumbent(const std::string& response) {
+ mock_protocol_handler_->SetCreateJobCallback(
+ base::Bind(&CreateResponseJob, response));
+ request_->Start();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(net::URLRequestStatus::SUCCESS, request_->status().status());
+ int incumbent_resource_id =
+ version_->script_cache_map()->LookupResourceId(script_url_);
+ EXPECT_NE(kInvalidServiceWorkerResponseId, incumbent_resource_id);
+
+ registration_->SetActiveVersion(version_);
+
+ // Teardown the request.
+ request_.reset();
+ url_request_context_.reset();
+ url_request_job_factory_.reset();
+ mock_protocol_handler_ = nullptr;
+ base::RunLoop().RunUntilIdle();
+
+ return incumbent_resource_id;
+ }
+
+ int GetResourceId(ServiceWorkerVersion* version) {
+ return version->script_cache_map()->LookupResourceId(script_url_);
+ }
+
+ // Performs the net request for an update of |registration_|'s incumbent
+ // to the script |response|. Returns the new version.
+ scoped_refptr<ServiceWorkerVersion> UpdateScript(
+ const std::string& response) {
+ int render_process_id = NextRenderProcessId();
+ int provider_id = NextProviderId();
+ scoped_refptr<ServiceWorkerVersion> new_version =
+ new ServiceWorkerVersion(registration_.get(), script_url_,
+ NextVersionId(), context()->AsWeakPtr());
+ CreateHostForVersion(render_process_id, provider_id, new_version);
+
+ SetUpScriptRequest(render_process_id, provider_id);
+ mock_protocol_handler_->SetCreateJobCallback(
+ base::Bind(&CreateResponseJob, response));
+ request_->Start();
+ base::RunLoop().RunUntilIdle();
+ return new_version;
+ }
+
+ void VerifyResource(int id, const std::string& expected) {
+ ASSERT_NE(kInvalidServiceWorkerResourceId, id);
+ bool is_equal = false;
+ scoped_ptr<ServiceWorkerResponseReader> reader =
+ context()->storage()->CreateResponseReader(id);
+ scoped_refptr<ResponseVerifier> verifier = new ResponseVerifier(
+ reader.Pass(), expected, CreateReceiverOnCurrentThread(&is_equal));
+ verifier->Start();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(is_equal);
+ }
+
ServiceWorkerContextCore* context() const { return helper_->context(); }
ServiceWorkerContextWrapper* context_wrapper() const {
return helper_->context_wrapper();
@@ -254,6 +408,10 @@ class ServiceWorkerWriteToCacheJobTest : public testing::Test {
MockURLRequestDelegate url_request_delegate_;
GURL scope_;
GURL script_url_;
+
+ int next_render_process_id_ = 1224; // dummy value
+ int next_provider_id_ = 1;
+ int64 next_version_id_ = 1L;
};
TEST_F(ServiceWorkerWriteToCacheJobTest, Normal) {
@@ -299,4 +457,118 @@ TEST_F(ServiceWorkerWriteToCacheJobTest, CertStatusError) {
version_->script_cache_map()->LookupResourceId(script_url_));
}
+TEST_F(ServiceWorkerWriteToCacheJobTest, Update_SameScript) {
+ std::string response = GenerateLongResponse();
+ CreateIncumbent(response);
+ scoped_refptr<ServiceWorkerVersion> version = UpdateScript(response);
+ EXPECT_EQ(kInvalidServiceWorkerResponseId, GetResourceId(version.get()));
+}
+
+TEST_F(ServiceWorkerWriteToCacheJobTest, Update_SameSizeScript) {
+ std::string response = GenerateLongResponse();
+ CreateIncumbent(response);
+
+ // Change the first byte.
+ response[0] = 'x';
+ scoped_refptr<ServiceWorkerVersion> version = UpdateScript(response);
+ VerifyResource(GetResourceId(version.get()), response);
+ registration_->SetWaitingVersion(version);
+
+ // Change something within the first block.
+ response[5555] = 'x';
+ version = UpdateScript(response);
+ VerifyResource(GetResourceId(version.get()), response);
+ registration_->SetWaitingVersion(version);
+
+ // Change something in a middle block.
+ response[kMiddleBlock * kBlockSize + 111] = 'x';
+ version = UpdateScript(response);
+ VerifyResource(GetResourceId(version.get()), response);
+ registration_->SetWaitingVersion(version);
+
+ // Change something within the last block.
+ response[(kNumBlocks - 1) * kBlockSize] = 'x';
+ version = UpdateScript(response);
+ VerifyResource(GetResourceId(version.get()), response);
+ registration_->SetWaitingVersion(version);
+
+ // Change the last byte.
+ response[(kNumBlocks * kBlockSize) - 1] = 'x';
+ version = UpdateScript(response);
+ VerifyResource(GetResourceId(version.get()), response);
+ registration_->SetWaitingVersion(version);
+}
+
+TEST_F(ServiceWorkerWriteToCacheJobTest, Update_TruncatedScript) {
+ std::string response = GenerateLongResponse();
+ CreateIncumbent(response);
+
+ // Truncate a single byte.
+ response.resize(response.size() - 1);
+ scoped_refptr<ServiceWorkerVersion> version = UpdateScript(response);
+ VerifyResource(GetResourceId(version.get()), response);
+ registration_->SetWaitingVersion(version);
+
+ // Truncate to a middle block.
+ response.resize((kMiddleBlock + 1) * kBlockSize + 111);
+ version = UpdateScript(response);
+ VerifyResource(GetResourceId(version.get()), response);
+ registration_->SetWaitingVersion(version);
+
+ // Truncate to a block boundary.
+ response.resize((kMiddleBlock - 1) * kBlockSize);
+ version = UpdateScript(response);
+ VerifyResource(GetResourceId(version.get()), response);
+ registration_->SetWaitingVersion(version);
+
+ // Truncate to a single byte.
+ response.resize(1);
+ version = UpdateScript(response);
+ VerifyResource(GetResourceId(version.get()), response);
+ registration_->SetWaitingVersion(version);
+}
+
+TEST_F(ServiceWorkerWriteToCacheJobTest, Update_ElongatedScript) {
+ std::string original_response = GenerateLongResponse();
+ CreateIncumbent(original_response);
+
+ // Extend a single byte.
+ std::string new_response = original_response + 'a';
+ scoped_refptr<ServiceWorkerVersion> version = UpdateScript(new_response);
+ VerifyResource(GetResourceId(version.get()), new_response);
+ registration_->SetWaitingVersion(version);
+
+ // Extend multiple blocks.
+ new_response = original_response + std::string(3 * kBlockSize, 'a');
+ version = UpdateScript(new_response);
+ VerifyResource(GetResourceId(version.get()), new_response);
+ registration_->SetWaitingVersion(version);
+
+ // Extend multiple blocks and bytes.
+ new_response = original_response + std::string(7 * kBlockSize + 777, 'a');
+ version = UpdateScript(new_response);
+ VerifyResource(GetResourceId(version.get()), new_response);
+ registration_->SetWaitingVersion(version);
+}
+
+TEST_F(ServiceWorkerWriteToCacheJobTest, Update_EmptyScript) {
+ // Create empty incumbent.
+ CreateIncumbent(std::string());
+
+ // Update from empty to non-empty.
+ std::string response = GenerateLongResponse();
+ scoped_refptr<ServiceWorkerVersion> version = UpdateScript(response);
+ VerifyResource(GetResourceId(version.get()), response);
+ registration_->SetWaitingVersion(version);
+
+ // Update from non-empty to empty.
+ version = UpdateScript(std::string());
+ VerifyResource(GetResourceId(version.get()), std::string());
+ registration_->SetWaitingVersion(version);
+
+ // Update from empty to empty.
+ version = UpdateScript(std::string());
+ EXPECT_EQ(kInvalidServiceWorkerResponseId, GetResourceId(version.get()));
+}
+
} // namespace content
« no previous file with comments | « content/browser/service_worker/service_worker_write_to_cache_job.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698