#include "base/callback.h"
#include "base/command_line.h"
#include "base/run_loop.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/browser/fileapi/chrome_blob_storage_context.h"
#include "content/browser/service_worker/embedded_worker_instance.h"
#include "content/browser/service_worker/embedded_worker_registry.h"
#include "content/browser/service_worker/service_worker_context_core.h"
+#include "content/browser/service_worker/service_worker_context_observer.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/browser/service_worker/service_worker_registration.h"
#include "content/browser/service_worker/service_worker_test_utils.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_switches.h"
+#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
#include "content/shell/browser/shell.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "net/test/embedded_test_server/http_request.h"
+#include "net/test/embedded_test_server/http_response.h"
+#include "net/url_request/url_request_filter.h"
+#include "net/url_request/url_request_interceptor.h"
+#include "net/url_request/url_request_test_job.h"
+#include "webkit/browser/blob/blob_data_handle.h"
+#include "webkit/browser/blob/blob_storage_context.h"
+#include "webkit/common/blob/blob_data.h"
namespace content {
ServiceWorkerStatusCode status;
ServiceWorkerFetchEventResult result;
ServiceWorkerResponse response;
+ scoped_ptr<webkit_blob::BlobDataHandle> blob_data_handle;
};
void RunAndQuit(const base::Closure& closure,
run_loop.Run();
}
+void RunOnIOThread(
+ const base::Callback<void(const base::Closure& continuation)>& closure) {
+ base::RunLoop run_loop;
+ base::Closure quit_on_original_thread =
+ base::Bind(base::IgnoreResult(&base::MessageLoopProxy::PostTask),
+ base::MessageLoopProxy::current().get(),
+ FROM_HERE,
+ run_loop.QuitClosure());
+ BrowserThread::PostTask(BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(closure, quit_on_original_thread));
+ run_loop.Run();
+}
+
// Contrary to the style guide, the output parameter of this function comes
// before input parameters so Bind can be used on it to create a FetchCallback
// to pass to DispatchFetchEvent.
void ReceiveFetchResult(BrowserThread::ID run_quit_thread,
const base::Closure& quit,
+ ChromeBlobStorageContext* blob_context,
FetchResult* out_result,
ServiceWorkerStatusCode actual_status,
ServiceWorkerFetchEventResult actual_result,
out_result->status = actual_status;
out_result->result = actual_result;
out_result->response = actual_response;
+ if (!actual_response.blob_uuid.empty()) {
+ out_result->blob_data_handle =
+ blob_context->context()->GetBlobDataFromUUID(
+ actual_response.blob_uuid);
+ }
if (!quit.is_null())
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, quit);
}
ServiceWorkerVersion::FetchCallback CreateResponseReceiver(
BrowserThread::ID run_quit_thread,
const base::Closure& quit,
+ ChromeBlobStorageContext* blob_context,
FetchResult* result) {
- return base::Bind(&ReceiveFetchResult, run_quit_thread, quit, result);
+ return base::Bind(&ReceiveFetchResult, run_quit_thread, quit,
+ make_scoped_refptr<ChromeBlobStorageContext>(blob_context),
+ result);
+}
+
+void ReadResponseBody(std::string* body,
+ webkit_blob::BlobDataHandle* blob_data_handle) {
+ ASSERT_TRUE(blob_data_handle);
+ ASSERT_EQ(1U, blob_data_handle->data()->items().size());
+ *body = std::string(blob_data_handle->data()->items()[0].bytes(),
+ blob_data_handle->data()->items()[0].length());
+}
+
+void ExpectResultAndRun(bool expected,
+ const base::Closure& continuation,
+ bool actual) {
+ EXPECT_EQ(expected, actual);
+ continuation.Run();
+}
+
+class WorkerActivatedObserver
+ : public ServiceWorkerContextObserver,
+ public base::RefCountedThreadSafe<WorkerActivatedObserver> {
+ public:
+ explicit WorkerActivatedObserver(ServiceWorkerContextWrapper* context)
+ : context_(context) {}
+ void Init() {
+ RunOnIOThread(base::Bind(&WorkerActivatedObserver::InitOnIOThread, this));
+ }
+ // ServiceWorkerContextObserver overrides.
+ virtual void OnVersionStateChanged(int64 version_id) OVERRIDE {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ const ServiceWorkerVersion* version =
+ context_->context()->GetLiveVersion(version_id);
+ if (version->status() == ServiceWorkerVersion::ACTIVATED) {
+ context_->RemoveObserver(this);
+ BrowserThread::PostTask(BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&WorkerActivatedObserver::Quit, this));
+ }
+ }
+ void Wait() { run_loop_.Run(); }
+
+ private:
+ friend class base::RefCountedThreadSafe<WorkerActivatedObserver>;
+ virtual ~WorkerActivatedObserver() {}
+ void InitOnIOThread() { context_->AddObserver(this); }
+ void Quit() { run_loop_.Quit(); }
+
+ base::RunLoop run_loop_;
+ ServiceWorkerContextWrapper* context_;
+ DISALLOW_COPY_AND_ASSIGN(WorkerActivatedObserver);
+};
+
+scoped_ptr<net::test_server::HttpResponse> VerifyServiceWorkerHeaderInRequest(
+ const net::test_server::HttpRequest& request) {
+ EXPECT_EQ(request.relative_url, "/service_worker/generated_sw.js");
+ std::map<std::string, std::string>::const_iterator it =
+ request.headers.find("Service-Worker");
+ EXPECT_TRUE(it != request.headers.end());
+ EXPECT_EQ("script", it->second);
+
+ scoped_ptr<net::test_server::BasicHttpResponse> http_response(
+ new net::test_server::BasicHttpResponse());
+ http_response->set_content_type("text/javascript");
+ return http_response.PassAs<net::test_server::HttpResponse>();
+}
+
+// The ImportsBustMemcache test requires that the imported script
+// would naturally be cached in blink's memcache, but the embedded
+// test server doesn't produce headers that allow the blink's memcache
+// to do that. This interceptor injects headers that give the import
+// an experiration far in the future.
+class LongLivedResourceInterceptor : public net::URLRequestInterceptor {
+ public:
+ LongLivedResourceInterceptor(const std::string& body)
+ : body_(body) {}
+ virtual ~LongLivedResourceInterceptor() {}
+
+ // net::URLRequestInterceptor implementation
+ virtual net::URLRequestJob* MaybeInterceptRequest(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate) const OVERRIDE {
+ const char kHeaders[] =
+ "HTTP/1.1 200 OK\0"
+ "Content-Type: text/javascript\0"
+ "Expires: Thu, 1 Jan 2100 20:00:00 GMT\0"
+ "\0";
+ std::string headers(kHeaders, arraysize(kHeaders));
+ return new net::URLRequestTestJob(
+ request, network_delegate, headers, body_, true);
+ }
+
+ private:
+ std::string body_;
+ DISALLOW_COPY_AND_ASSIGN(LongLivedResourceInterceptor);
+};
+
+void CreateLongLivedResourceInterceptors(
+ const GURL& worker_url, const GURL& import_url) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ scoped_ptr<net::URLRequestInterceptor> interceptor;
+
+ interceptor.reset(new LongLivedResourceInterceptor(
+ "importScripts('long_lived_import.js');"));
+ net::URLRequestFilter::GetInstance()->AddUrlInterceptor(
+ worker_url, interceptor.Pass());
+
+ interceptor.reset(new LongLivedResourceInterceptor(
+ "// the imported script does nothing"));
+ net::URLRequestFilter::GetInstance()->AddUrlInterceptor(
+ import_url, interceptor.Pass());
+}
+
+void CountScriptResources(
+ ServiceWorkerContextWrapper* wrapper,
+ const GURL& scope,
+ int* num_resources) {
+ *num_resources = -1;
+
+ std::vector<ServiceWorkerRegistrationInfo> infos =
+ wrapper->context()->GetAllLiveRegistrationInfo();
+ if (infos.empty())
+ return;
+
+ int version_id;
+ size_t index = infos.size() - 1;
+ if (!infos[index].installing_version.is_null)
+ version_id = infos[index].installing_version.version_id;
+ else if (!infos[index].waiting_version.is_null)
+ version_id = infos[1].waiting_version.version_id;
+ else if (!infos[index].active_version.is_null)
+ version_id = infos[index].active_version.version_id;
+ else
+ return;
+
+ ServiceWorkerVersion* version =
+ wrapper->context()->GetLiveVersion(version_id);
+ *num_resources = static_cast<int>(version->script_cache_map()->size());
}
} // namespace
protected:
typedef ServiceWorkerBrowserTest self;
- virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
- command_line->AppendSwitch(switches::kEnableServiceWorker);
+ virtual void SetUpCommandLine(base::CommandLine* command_line) OVERRIDE {
+ command_line->AppendSwitch(
+ switches::kEnableExperimentalWebPlatformFeatures);
}
virtual void SetUpOnMainThread() OVERRIDE {
ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
StoragePartition* partition = BrowserContext::GetDefaultStoragePartition(
shell()->web_contents()->GetBrowserContext());
- wrapper_ = partition->GetServiceWorkerContext();
+ wrapper_ = static_cast<ServiceWorkerContextWrapper*>(
+ partition->GetServiceWorkerContext());
// Navigate to the page to set up a renderer page (where we can embed
// a worker).
virtual void TearDownOnIOThread() {}
ServiceWorkerContextWrapper* wrapper() { return wrapper_.get(); }
+ ServiceWorkerContext* public_context() { return wrapper(); }
void AssociateRendererProcessToWorker(EmbeddedWorkerInstance* worker) {
worker->AddProcessReference(
};
class EmbeddedWorkerBrowserTest : public ServiceWorkerBrowserTest,
- public EmbeddedWorkerInstance::Observer {
+ public EmbeddedWorkerInstance::Listener {
public:
typedef EmbeddedWorkerBrowserTest self;
EmbeddedWorkerBrowserTest()
- : last_worker_status_(EmbeddedWorkerInstance::STOPPED) {}
+ : last_worker_status_(EmbeddedWorkerInstance::STOPPED),
+ pause_mode_(DONT_PAUSE) {}
virtual ~EmbeddedWorkerBrowserTest() {}
virtual void TearDownOnIOThread() OVERRIDE {
if (worker_) {
- worker_->RemoveObserver(this);
+ worker_->RemoveListener(this);
worker_.reset();
}
}
ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
worker_ = wrapper()->context()->embedded_worker_registry()->CreateWorker();
EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker_->status());
- worker_->AddObserver(this);
+ worker_->AddListener(this);
AssociateRendererProcessToWorker(worker_.get());
const int64 service_worker_version_id = 33L;
+ const GURL scope = embedded_test_server()->GetURL("/");
const GURL script_url = embedded_test_server()->GetURL(
"/service_worker/worker.js");
- ServiceWorkerStatusCode status = worker_->Start(
- service_worker_version_id, script_url);
-
+ std::vector<int> processes;
+ processes.push_back(
+ shell()->web_contents()->GetRenderProcessHost()->GetID());
+ worker_->Start(
+ service_worker_version_id,
+ scope,
+ script_url,
+ pause_mode_ != DONT_PAUSE,
+ processes,
+ base::Bind(&EmbeddedWorkerBrowserTest::StartOnIOThread2, this));
+ }
+ void StartOnIOThread2(ServiceWorkerStatusCode status) {
last_worker_status_ = worker_->status();
EXPECT_EQ(SERVICE_WORKER_OK, status);
EXPECT_EQ(EmbeddedWorkerInstance::STARTING, last_worker_status_);
last_worker_status_ = worker_->status();
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, done_closure_);
}
- virtual void OnMessageReceived(
- int request_id, const IPC::Message& message) OVERRIDE {
- NOTREACHED();
+ virtual void OnPausedAfterDownload() OVERRIDE {
+ if (pause_mode_ == PAUSE_THEN_RESUME)
+ worker_->ResumeAfterDownload();
+ else if (pause_mode_ == PAUSE_THEN_STOP)
+ worker_->Stop();
+ else
+ ASSERT_TRUE(false);
+ }
+ virtual void OnReportException(const base::string16& error_message,
+ int line_number,
+ int column_number,
+ const GURL& source_url) OVERRIDE {}
+ virtual void OnReportConsoleMessage(int source_identifier,
+ int message_level,
+ const base::string16& message,
+ int line_number,
+ const GURL& source_url) OVERRIDE {}
+ virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
+ return false;
}
scoped_ptr<EmbeddedWorkerInstance> worker_;
EmbeddedWorkerInstance::Status last_worker_status_;
+ enum {
+ DONT_PAUSE,
+ PAUSE_THEN_RESUME,
+ PAUSE_THEN_STOP,
+ } pause_mode_;
+
// Called by EmbeddedWorkerInstance::Observer overrides so that
// test code can wait for the worker status notifications.
base::Closure done_closure_;
public:
typedef ServiceWorkerVersionBrowserTest self;
- ServiceWorkerVersionBrowserTest() : next_registration_id_(1) {}
virtual ~ServiceWorkerVersionBrowserTest() {}
virtual void TearDownOnIOThread() OVERRIDE {
- if (registration_) {
- registration_->Shutdown();
- registration_ = NULL;
- }
- if (version_) {
- version_->Shutdown();
- version_ = NULL;
- }
+ registration_ = NULL;
+ version_ = NULL;
}
- void InstallTestHelper(const std::string& worker_url) {
+ void InstallTestHelper(const std::string& worker_url,
+ ServiceWorkerStatusCode expected_status) {
RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread, this,
worker_url));
install_run_loop.QuitClosure(),
&status));
install_run_loop.Run();
- ASSERT_EQ(SERVICE_WORKER_OK, status);
+ ASSERT_EQ(expected_status, status);
// Stop the worker.
status = SERVICE_WORKER_ERROR_FAILED;
ASSERT_EQ(SERVICE_WORKER_OK, status);
}
- void FetchTestHelper(const std::string& worker_url,
- ServiceWorkerFetchEventResult* result,
- ServiceWorkerResponse* response) {
+ void ActivateTestHelper(
+ const std::string& worker_url,
+ ServiceWorkerStatusCode expected_status) {
RunOnIOThread(
base::Bind(&self::SetUpRegistrationOnIOThread, this, worker_url));
+ ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
+ base::RunLoop run_loop;
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(
+ &self::ActivateOnIOThread, this, run_loop.QuitClosure(), &status));
+ run_loop.Run();
+ ASSERT_EQ(expected_status, status);
+ }
+ void FetchOnRegisteredWorker(
+ ServiceWorkerFetchEventResult* result,
+ ServiceWorkerResponse* response,
+ scoped_ptr<webkit_blob::BlobDataHandle>* blob_data_handle) {
+ blob_context_ = ChromeBlobStorageContext::GetFor(
+ shell()->web_contents()->GetBrowserContext());
FetchResult fetch_result;
fetch_result.status = SERVICE_WORKER_ERROR_FAILED;
base::RunLoop fetch_run_loop;
fetch_run_loop.Run();
*result = fetch_result.result;
*response = fetch_result.response;
+ *blob_data_handle = fetch_result.blob_data_handle.Pass();
ASSERT_EQ(SERVICE_WORKER_OK, fetch_result.status);
}
+ void FetchTestHelper(
+ const std::string& worker_url,
+ ServiceWorkerFetchEventResult* result,
+ ServiceWorkerResponse* response,
+ scoped_ptr<webkit_blob::BlobDataHandle>* blob_data_handle) {
+ RunOnIOThread(
+ base::Bind(&self::SetUpRegistrationOnIOThread, this, worker_url));
+ FetchOnRegisteredWorker(result, response, blob_data_handle);
+ }
+
void SetUpRegistrationOnIOThread(const std::string& worker_url) {
- const int64 version_id = 1L;
registration_ = new ServiceWorkerRegistration(
- embedded_test_server()->GetURL("/*"),
+ embedded_test_server()->GetURL("/"),
embedded_test_server()->GetURL(worker_url),
- next_registration_id_++);
+ wrapper()->context()->storage()->NewRegistrationId(),
+ wrapper()->context()->AsWeakPtr());
version_ = new ServiceWorkerVersion(
registration_,
- wrapper()->context()->embedded_worker_registry(),
- version_id);
+ wrapper()->context()->storage()->NewVersionId(),
+ wrapper()->context()->AsWeakPtr());
AssociateRendererProcessToWorker(version_->embedded_worker());
}
void InstallOnIOThread(const base::Closure& done,
ServiceWorkerStatusCode* result) {
ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ version_->SetStatus(ServiceWorkerVersion::INSTALLING);
version_->DispatchInstallEvent(
-1, CreateReceiver(BrowserThread::UI, done, result));
}
+ void ActivateOnIOThread(const base::Closure& done,
+ ServiceWorkerStatusCode* result) {
+ ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ version_->SetStatus(ServiceWorkerVersion::ACTIVATING);
+ version_->DispatchActivateEvent(
+ CreateReceiver(BrowserThread::UI, done, result));
+ }
+
void FetchOnIOThread(const base::Closure& done, FetchResult* result) {
ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
ServiceWorkerFetchRequest request(
embedded_test_server()->GetURL("/service_worker/empty.html"),
"GET",
- std::map<std::string, std::string>());
- version_->SetStatus(ServiceWorkerVersion::ACTIVE);
+ std::map<std::string, std::string>(),
+ GURL(""),
+ false);
+ version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
version_->DispatchFetchEvent(
- request, CreateResponseReceiver(BrowserThread::UI, done, result));
+ request, CreateResponseReceiver(BrowserThread::UI, done,
+ blob_context_, result));
}
void StopOnIOThread(const base::Closure& done,
version_->StopWorker(CreateReceiver(BrowserThread::UI, done, result));
}
+ void SyncEventOnIOThread(const base::Closure& done,
+ ServiceWorkerStatusCode* result) {
+ ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
+ version_->DispatchSyncEvent(
+ CreateReceiver(BrowserThread::UI, done, result));
+ }
+
protected:
- int64 next_registration_id_;
scoped_refptr<ServiceWorkerRegistration> registration_;
scoped_refptr<ServiceWorkerVersion> version_;
+ scoped_refptr<ChromeBlobStorageContext> blob_context_;
};
IN_PROC_BROWSER_TEST_F(EmbeddedWorkerBrowserTest, StartAndStop) {
ASSERT_EQ(EmbeddedWorkerInstance::STOPPED, last_worker_status_);
}
+IN_PROC_BROWSER_TEST_F(EmbeddedWorkerBrowserTest, StartPaused_ThenResume) {
+ pause_mode_ = PAUSE_THEN_RESUME;
+ base::RunLoop start_run_loop;
+ done_closure_ = start_run_loop.QuitClosure();
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+ base::Bind(&self::StartOnIOThread, this));
+ start_run_loop.Run();
+ ASSERT_EQ(EmbeddedWorkerInstance::RUNNING, last_worker_status_);
+}
+
+IN_PROC_BROWSER_TEST_F(EmbeddedWorkerBrowserTest,
+ StartPaused_ThenStop) {
+ pause_mode_ = PAUSE_THEN_STOP;
+ base::RunLoop start_run_loop;
+ done_closure_ = start_run_loop.QuitClosure();
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+ base::Bind(&self::StartOnIOThread, this));
+ start_run_loop.Run();
+ ASSERT_EQ(EmbeddedWorkerInstance::STOPPED, last_worker_status_);
+}
+
IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, StartAndStop) {
RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread, this,
"/service_worker/worker.js"));
}
IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, Install) {
- InstallTestHelper("/service_worker/worker.js");
+ InstallTestHelper("/service_worker/worker.js", SERVICE_WORKER_OK);
}
IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
InstallWithWaitUntil_Fulfilled) {
- InstallTestHelper("/service_worker/worker_install_fulfilled.js");
+ InstallTestHelper("/service_worker/worker_install_fulfilled.js",
+ SERVICE_WORKER_OK);
+}
+
+// Check that ServiceWorker script requests set a "Service-Worker: script"
+// header.
+IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
+ ServiceWorkerScriptHeader) {
+ embedded_test_server()->RegisterRequestHandler(
+ base::Bind(&VerifyServiceWorkerHeaderInRequest));
+ InstallTestHelper("/service_worker/generated_sw.js", SERVICE_WORKER_OK);
+}
+
+IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
+ Activate_NoEventListener) {
+ ActivateTestHelper("/service_worker/worker.js", SERVICE_WORKER_OK);
+ ASSERT_EQ(ServiceWorkerVersion::ACTIVATING, version_->status());
+}
+
+IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, Activate_Rejected) {
+ ActivateTestHelper("/service_worker/worker_activate_rejected.js",
+ SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED);
}
IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
InstallWithWaitUntil_Rejected) {
- // TODO(kinuko): This should also report back an error, but we
- // don't have plumbing for it yet.
- InstallTestHelper("/service_worker/worker_install_rejected.js");
+ InstallTestHelper("/service_worker/worker_install_rejected.js",
+ SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED);
}
IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, FetchEvent_Response) {
ServiceWorkerFetchEventResult result;
ServiceWorkerResponse response;
- FetchTestHelper("/service_worker/fetch_event.js", &result, &response);
+ scoped_ptr<webkit_blob::BlobDataHandle> blob_data_handle;
+ FetchTestHelper("/service_worker/fetch_event.js",
+ &result, &response, &blob_data_handle);
ASSERT_EQ(SERVICE_WORKER_FETCH_EVENT_RESULT_RESPONSE, result);
- EXPECT_EQ(200, response.status_code);
- EXPECT_EQ("OK", response.status_text);
- EXPECT_EQ("GET", response.method);
+ EXPECT_EQ(301, response.status_code);
+ EXPECT_EQ("Moved Permanently", response.status_text);
std::map<std::string, std::string> expected_headers;
+ expected_headers["content-language"] = "fi";
+ expected_headers["content-type"] = "text/html; charset=UTF-8";
EXPECT_EQ(expected_headers, response.headers);
+
+ std::string body;
+ RunOnIOThread(
+ base::Bind(&ReadResponseBody,
+ &body, base::Owned(blob_data_handle.release())));
+ EXPECT_EQ("This resource is gone. Gone, gone, gone.", body);
}
IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
- FetchEvent_FallbackToNative) {
- ServiceWorkerFetchEventResult result;
- ServiceWorkerResponse response;
- FetchTestHelper(
- "/service_worker/fetch_event_fallback.js", &result, &response);
- ASSERT_EQ(SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK, result);
+ SyncAbortedWithoutFlag) {
+ RunOnIOThread(base::Bind(
+ &self::SetUpRegistrationOnIOThread, this, "/service_worker/sync.js"));
+
+ // Run the sync event.
+ ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
+ base::RunLoop sync_run_loop;
+ BrowserThread::PostTask(BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&self::SyncEventOnIOThread,
+ this,
+ sync_run_loop.QuitClosure(),
+ &status));
+ sync_run_loop.Run();
+ ASSERT_EQ(SERVICE_WORKER_ERROR_ABORT, status);
}
-IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, FetchEvent_Rejected) {
+IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, SyncEventHandled) {
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ command_line->AppendSwitch(switches::kEnableServiceWorkerSync);
+
+ RunOnIOThread(base::Bind(
+ &self::SetUpRegistrationOnIOThread, this, "/service_worker/sync.js"));
ServiceWorkerFetchEventResult result;
ServiceWorkerResponse response;
- FetchTestHelper("/service_worker/fetch_event_error.js", &result, &response);
- ASSERT_EQ(SERVICE_WORKER_FETCH_EVENT_RESULT_FALLBACK, result);
+ scoped_ptr<webkit_blob::BlobDataHandle> blob_data_handle;
+ // Should 404 before sync event.
+ FetchOnRegisteredWorker(&result, &response, &blob_data_handle);
+ EXPECT_EQ(404, response.status_code);
+
+ // Run the sync event.
+ ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
+ base::RunLoop sync_run_loop;
+ BrowserThread::PostTask(BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&self::SyncEventOnIOThread,
+ this,
+ sync_run_loop.QuitClosure(),
+ &status));
+ sync_run_loop.Run();
+ ASSERT_EQ(SERVICE_WORKER_OK, status);
+
+ // Should 200 after sync event.
+ FetchOnRegisteredWorker(&result, &response, &blob_data_handle);
+ EXPECT_EQ(200, response.status_code);
+}
+
+// ServiceWorkerBrowserTest.Reload is flaky on Android crbug.com/393486
+#if defined(OS_ANDROID)
+#define MAYBE_Reload DISABLED_Reload
+#else
+#define MAYBE_Reload Reload
+#endif
+IN_PROC_BROWSER_TEST_F(ServiceWorkerBrowserTest, MAYBE_Reload) {
+ const std::string kPageUrl = "/service_worker/reload.html";
+ const std::string kWorkerUrl = "/service_worker/fetch_event_reload.js";
+ {
+ scoped_refptr<WorkerActivatedObserver> observer =
+ new WorkerActivatedObserver(wrapper());
+ observer->Init();
+ public_context()->RegisterServiceWorker(
+ embedded_test_server()->GetURL(kPageUrl),
+ embedded_test_server()->GetURL(kWorkerUrl),
+ base::Bind(&ExpectResultAndRun, true, base::Bind(&base::DoNothing)));
+ observer->Wait();
+ }
+ {
+ const base::string16 title = base::ASCIIToUTF16("reload=false");
+ TitleWatcher title_watcher(shell()->web_contents(), title);
+ NavigateToURL(shell(), embedded_test_server()->GetURL(kPageUrl));
+ EXPECT_EQ(title, title_watcher.WaitAndGetTitle());
+ }
+ {
+ const base::string16 title = base::ASCIIToUTF16("reload=true");
+ TitleWatcher title_watcher(shell()->web_contents(), title);
+ ReloadBlockUntilNavigationsComplete(shell(), 1);
+ EXPECT_EQ(title, title_watcher.WaitAndGetTitle());
+ }
+ shell()->Close();
+ {
+ base::RunLoop run_loop;
+ public_context()->UnregisterServiceWorker(
+ embedded_test_server()->GetURL(kPageUrl),
+ base::Bind(&ExpectResultAndRun, true, run_loop.QuitClosure()));
+ run_loop.Run();
+ }
+}
+
+IN_PROC_BROWSER_TEST_F(ServiceWorkerBrowserTest, ImportsBustMemcache) {
+ const std::string kScopeUrl = "/service_worker/imports_bust_memcache_scope/";
+ const std::string kPageUrl = "/service_worker/imports_bust_memcache.html";
+ const std::string kScriptUrl = "/service_worker/worker_with_one_import.js";
+ const std::string kImportUrl = "/service_worker/long_lived_import.js";
+ const base::string16 kOKTitle(base::ASCIIToUTF16("OK"));
+ const base::string16 kFailTitle(base::ASCIIToUTF16("FAIL"));
+
+ RunOnIOThread(
+ base::Bind(&CreateLongLivedResourceInterceptors,
+ embedded_test_server()->GetURL(kScriptUrl),
+ embedded_test_server()->GetURL(kImportUrl)));
+
+ TitleWatcher title_watcher(shell()->web_contents(), kOKTitle);
+ title_watcher.AlsoWaitForTitle(kFailTitle);
+ NavigateToURL(shell(), embedded_test_server()->GetURL(kPageUrl));
+ base::string16 title = title_watcher.WaitAndGetTitle();
+ EXPECT_EQ(kOKTitle, title);
+
+ // Verify the number of resources in the implicit script cache is correct.
+ const int kExpectedNumResources = 2;
+ int num_resources = 0;
+ RunOnIOThread(
+ base::Bind(&CountScriptResources,
+ base::Unretained(wrapper()),
+ embedded_test_server()->GetURL(kScopeUrl),
+ &num_resources));
+ EXPECT_EQ(kExpectedNumResources, num_resources);
+}
+
+class ServiceWorkerBlackBoxBrowserTest : public ServiceWorkerBrowserTest {
+ public:
+ typedef ServiceWorkerBlackBoxBrowserTest self;
+
+ void FindRegistrationOnIO(const GURL& document_url,
+ ServiceWorkerStatusCode* status,
+ GURL* script_url,
+ const base::Closure& continuation) {
+ wrapper()->context()->storage()->FindRegistrationForDocument(
+ document_url,
+ base::Bind(&ServiceWorkerBlackBoxBrowserTest::FindRegistrationOnIO2,
+ this,
+ status,
+ script_url,
+ continuation));
+ }
+
+ void FindRegistrationOnIO2(
+ ServiceWorkerStatusCode* out_status,
+ GURL* script_url,
+ const base::Closure& continuation,
+ ServiceWorkerStatusCode status,
+ const scoped_refptr<ServiceWorkerRegistration>& registration) {
+ *out_status = status;
+ if (registration) {
+ *script_url = registration->script_url();
+ } else {
+ EXPECT_NE(SERVICE_WORKER_OK, status);
+ }
+ continuation.Run();
+ }
+};
+
+static int CountRenderProcessHosts() {
+ int result = 0;
+ for (RenderProcessHost::iterator iter(RenderProcessHost::AllHostsIterator());
+ !iter.IsAtEnd();
+ iter.Advance()) {
+ result++;
+ }
+ return result;
+}
+
+// Crashes on Android and flakes on CrOS: http://crbug.com/387045
+#if defined(OS_ANDROID) || defined(OS_CHROMEOS)
+#define MAYBE_Registration DISABLED_Registration
+#else
+#define MAYBE_Registration Registration
+#endif
+IN_PROC_BROWSER_TEST_F(ServiceWorkerBlackBoxBrowserTest, MAYBE_Registration) {
+ // Close the only window to be sure we're not re-using its RenderProcessHost.
+ shell()->Close();
+ EXPECT_EQ(0, CountRenderProcessHosts());
+
+ const std::string kWorkerUrl = "/service_worker/fetch_event.js";
+
+ // Unregistering nothing should return true.
+ {
+ base::RunLoop run_loop;
+ public_context()->UnregisterServiceWorker(
+ embedded_test_server()->GetURL("/"),
+ base::Bind(&ExpectResultAndRun, true, run_loop.QuitClosure()));
+ run_loop.Run();
+ }
+
+ // If we use a worker URL that doesn't exist, registration fails.
+ {
+ base::RunLoop run_loop;
+ public_context()->RegisterServiceWorker(
+ embedded_test_server()->GetURL("/"),
+ embedded_test_server()->GetURL("/does/not/exist"),
+ base::Bind(&ExpectResultAndRun, false, run_loop.QuitClosure()));
+ run_loop.Run();
+ }
+ EXPECT_EQ(0, CountRenderProcessHosts());
+
+ // Register returns when the promise would be resolved.
+ {
+ base::RunLoop run_loop;
+ public_context()->RegisterServiceWorker(
+ embedded_test_server()->GetURL("/"),
+ embedded_test_server()->GetURL(kWorkerUrl),
+ base::Bind(&ExpectResultAndRun, true, run_loop.QuitClosure()));
+ run_loop.Run();
+ }
+ EXPECT_EQ(1, CountRenderProcessHosts());
+
+ // Registering again should succeed, although the algo still
+ // might not be complete.
+ {
+ base::RunLoop run_loop;
+ public_context()->RegisterServiceWorker(
+ embedded_test_server()->GetURL("/"),
+ embedded_test_server()->GetURL(kWorkerUrl),
+ base::Bind(&ExpectResultAndRun, true, run_loop.QuitClosure()));
+ run_loop.Run();
+ }
+
+ // The registration algo might not be far enough along to have
+ // stored the registration data, so it may not be findable
+ // at this point.
+
+ // Unregistering something should return true.
+ {
+ base::RunLoop run_loop;
+ public_context()->UnregisterServiceWorker(
+ embedded_test_server()->GetURL("/"),
+ base::Bind(&ExpectResultAndRun, true, run_loop.QuitClosure()));
+ run_loop.Run();
+ }
+ EXPECT_GE(1, CountRenderProcessHosts()) << "Unregistering doesn't stop the "
+ "workers eagerly, so their RPHs "
+ "can still be running.";
+
+ // Should not be able to find it.
+ {
+ ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
+ GURL script_url;
+ RunOnIOThread(
+ base::Bind(&ServiceWorkerBlackBoxBrowserTest::FindRegistrationOnIO,
+ this,
+ embedded_test_server()->GetURL("/service_worker/empty.html"),
+ &status,
+ &script_url));
+ EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND, status);
+ }
}
} // namespace content