1885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org// Copyright 2014 The Chromium Authors. All rights reserved.
2885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org// Use of this source code is governed by a BSD-style license that can be
3885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org// found in the LICENSE file.
4885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
5885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "base/bind.h"
6885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "base/callback.h"
7885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "base/command_line.h"
8885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "base/run_loop.h"
9885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "base/strings/utf_string_conversions.h"
10885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "content/browser/fileapi/chrome_blob_storage_context.h"
11e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#include "content/browser/service_worker/embedded_worker_instance.h"
12885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "content/browser/service_worker/embedded_worker_registry.h"
13885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "content/browser/service_worker/service_worker_context_core.h"
14885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "content/browser/service_worker/service_worker_context_observer.h"
15e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#include "content/browser/service_worker/service_worker_context_wrapper.h"
16885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "content/browser/service_worker/service_worker_registration.h"
17885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "content/browser/service_worker/service_worker_test_utils.h"
18885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "content/browser/service_worker/service_worker_version.h"
19885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "content/common/service_worker/service_worker_messages.h"
20885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "content/common/service_worker/service_worker_status_code.h"
21885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "content/common/service_worker/service_worker_types.h"
22885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "content/public/browser/browser_context.h"
23885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "content/public/browser/browser_thread.h"
24885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "content/public/browser/render_process_host.h"
25885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "content/public/browser/storage_partition.h"
26885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "content/public/browser/web_contents.h"
27885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "content/public/common/content_switches.h"
28885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "content/public/test/browser_test_utils.h"
29885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "content/public/test/content_browser_test.h"
30885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "content/public/test/content_browser_test_utils.h"
31885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "content/shell/browser/shell.h"
32885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "net/test/embedded_test_server/embedded_test_server.h"
33e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org#include "net/test/embedded_test_server/http_request.h"
34885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "net/test/embedded_test_server/http_response.h"
35885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "net/url_request/url_request_filter.h"
36885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "net/url_request/url_request_interceptor.h"
37885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "net/url_request/url_request_test_job.h"
38885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "storage/browser/blob/blob_data_handle.h"
39885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org#include "storage/browser/blob/blob_storage_context.h"
403c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com#include "storage/common/blob/blob_data.h"
41885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
42885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgnamespace content {
43885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
44885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgnamespace {
45885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
46885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgstruct FetchResult {
47885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  ServiceWorkerStatusCode status;
48885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  ServiceWorkerFetchEventResult result;
49885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  ServiceWorkerResponse response;
50885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  scoped_ptr<storage::BlobDataHandle> blob_data_handle;
51885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org};
52885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
53885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgvoid RunAndQuit(const base::Closure& closure,
54885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                const base::Closure& quit,
55885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                base::MessageLoopProxy* original_message_loop) {
56885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  closure.Run();
57885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  original_message_loop->PostTask(FROM_HERE, quit);
58885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
593c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com
60885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgvoid RunOnIOThread(const base::Closure& closure) {
61885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  base::RunLoop run_loop;
62885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  BrowserThread::PostTask(
63885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      BrowserThread::IO, FROM_HERE,
64885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      base::Bind(&RunAndQuit, closure, run_loop.QuitClosure(),
65885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                 base::MessageLoopProxy::current()));
66885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  run_loop.Run();
67885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
68885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
69885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgvoid RunOnIOThread(
70885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    const base::Callback<void(const base::Closure& continuation)>& closure) {
71885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  base::RunLoop run_loop;
72885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  base::Closure quit_on_original_thread =
73885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      base::Bind(base::IgnoreResult(&base::MessageLoopProxy::PostTask),
74885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                 base::MessageLoopProxy::current().get(),
75885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                 FROM_HERE,
76885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                 run_loop.QuitClosure());
77885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  BrowserThread::PostTask(BrowserThread::IO,
78885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                          FROM_HERE,
79885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                          base::Bind(closure, quit_on_original_thread));
80885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  run_loop.Run();
81885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
82885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
83885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgvoid ReceivePrepareResult(bool* is_prepared) {
84885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  *is_prepared = true;
85885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
86885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
87885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgbase::Closure CreatePrepareReceiver(bool* is_prepared) {
88885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  return base::Bind(&ReceivePrepareResult, is_prepared);
89885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
90885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
91885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org// Contrary to the style guide, the output parameter of this function comes
92885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org// before input parameters so Bind can be used on it to create a FetchCallback
93885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org// to pass to DispatchFetchEvent.
94885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgvoid ReceiveFetchResult(BrowserThread::ID run_quit_thread,
95885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                        const base::Closure& quit,
96885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                        ChromeBlobStorageContext* blob_context,
97885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                        FetchResult* out_result,
98885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                        ServiceWorkerStatusCode actual_status,
99885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                        ServiceWorkerFetchEventResult actual_result,
100885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                        const ServiceWorkerResponse& actual_response) {
101885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  out_result->status = actual_status;
102885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  out_result->result = actual_result;
103885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  out_result->response = actual_response;
104885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  if (!actual_response.blob_uuid.empty()) {
105885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    out_result->blob_data_handle =
106885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        blob_context->context()->GetBlobDataFromUUID(
107885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org            actual_response.blob_uuid);
108885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  }
109885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  if (!quit.is_null())
110885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, quit);
111885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
112885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
113885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgServiceWorkerVersion::FetchCallback CreateResponseReceiver(
114885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    BrowserThread::ID run_quit_thread,
115885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    const base::Closure& quit,
116885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    ChromeBlobStorageContext* blob_context,
117885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    FetchResult* result) {
118885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  return base::Bind(&ReceiveFetchResult, run_quit_thread, quit,
119885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                    make_scoped_refptr<ChromeBlobStorageContext>(blob_context),
120885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                    result);
121885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
122885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
123885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgvoid ReadResponseBody(std::string* body,
124885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                      storage::BlobDataHandle* blob_data_handle) {
125885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  ASSERT_TRUE(blob_data_handle);
126885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  ASSERT_EQ(1U, blob_data_handle->data()->items().size());
127885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  *body = std::string(blob_data_handle->data()->items()[0].bytes(),
128885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                      blob_data_handle->data()->items()[0].length());
129885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
130885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
131885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgvoid ExpectResultAndRun(bool expected,
132885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                        const base::Closure& continuation,
133885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                        bool actual) {
134885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  EXPECT_EQ(expected, actual);
135885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  continuation.Run();
136885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
137885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
138885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgclass WorkerActivatedObserver
139885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    : public ServiceWorkerContextObserver,
140885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      public base::RefCountedThreadSafe<WorkerActivatedObserver> {
141885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org public:
142885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  explicit WorkerActivatedObserver(ServiceWorkerContextWrapper* context)
143885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      : context_(context) {}
144885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  void Init() {
145885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    RunOnIOThread(base::Bind(&WorkerActivatedObserver::InitOnIOThread, this));
146885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  }
147885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  // ServiceWorkerContextObserver overrides.
1483c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com  virtual void OnVersionStateChanged(int64 version_id) OVERRIDE {
1493c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com    DCHECK_CURRENTLY_ON(BrowserThread::IO);
150885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    const ServiceWorkerVersion* version =
151885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        context_->context()->GetLiveVersion(version_id);
152885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    if (version->status() == ServiceWorkerVersion::ACTIVATED) {
153885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      context_->RemoveObserver(this);
154885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      BrowserThread::PostTask(BrowserThread::UI,
155885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                              FROM_HERE,
156885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                              base::Bind(&WorkerActivatedObserver::Quit, this));
157885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
158885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  }
159885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  void Wait() { run_loop_.Run(); }
160885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
161e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org private:
162885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  friend class base::RefCountedThreadSafe<WorkerActivatedObserver>;
163e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org  virtual ~WorkerActivatedObserver() {}
164885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  void InitOnIOThread() { context_->AddObserver(this); }
165885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  void Quit() { run_loop_.Quit(); }
166885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
167885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  base::RunLoop run_loop_;
168885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  ServiceWorkerContextWrapper* context_;
169885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  DISALLOW_COPY_AND_ASSIGN(WorkerActivatedObserver);
170885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org};
171885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
172885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgscoped_ptr<net::test_server::HttpResponse> VerifyServiceWorkerHeaderInRequest(
173885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    const net::test_server::HttpRequest& request) {
174885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  EXPECT_EQ(request.relative_url, "/service_worker/generated_sw.js");
175885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  std::map<std::string, std::string>::const_iterator it =
176885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      request.headers.find("Service-Worker");
177885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  EXPECT_TRUE(it != request.headers.end());
178885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  EXPECT_EQ("script", it->second);
179885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
180885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  scoped_ptr<net::test_server::BasicHttpResponse> http_response(
181885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      new net::test_server::BasicHttpResponse());
182885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  http_response->set_content_type("text/javascript");
183885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  return http_response.PassAs<net::test_server::HttpResponse>();
184885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
185885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
186885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org// The ImportsBustMemcache test requires that the imported script
187885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org// would naturally be cached in blink's memcache, but the embedded
188885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org// test server doesn't produce headers that allow the blink's memcache
189885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org// to do that. This interceptor injects headers that give the import
190885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org// an experiration far in the future.
191885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgclass LongLivedResourceInterceptor : public net::URLRequestInterceptor {
192885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org public:
193885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  LongLivedResourceInterceptor(const std::string& body)
194885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      : body_(body) {}
195885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  virtual ~LongLivedResourceInterceptor() {}
196885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
197885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  // net::URLRequestInterceptor implementation
198885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  virtual net::URLRequestJob* MaybeInterceptRequest(
199885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      net::URLRequest* request,
200885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      net::NetworkDelegate* network_delegate) const OVERRIDE {
201885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    const char kHeaders[] =
202885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        "HTTP/1.1 200 OK\0"
203885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        "Content-Type: text/javascript\0"
204885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        "Expires: Thu, 1 Jan 2100 20:00:00 GMT\0"
2056b6bee25314cfac02cc555cddedb9680c63a26d6sergeyu@chromium.org        "\0";
206885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    std::string headers(kHeaders, arraysize(kHeaders));
207885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    return new net::URLRequestTestJob(
208885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        request, network_delegate, headers, body_, true);
209885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  }
210885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
211885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org private:
212885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  std::string body_;
213885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  DISALLOW_COPY_AND_ASSIGN(LongLivedResourceInterceptor);
214885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org};
215885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
216885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgvoid CreateLongLivedResourceInterceptors(
217885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    const GURL& worker_url, const GURL& import_url) {
218885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
219885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  scoped_ptr<net::URLRequestInterceptor> interceptor;
220885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
221885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  interceptor.reset(new LongLivedResourceInterceptor(
222885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      "importScripts('long_lived_import.js');"));
223885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  net::URLRequestFilter::GetInstance()->AddUrlInterceptor(
224885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      worker_url, interceptor.Pass());
225885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
226885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  interceptor.reset(new LongLivedResourceInterceptor(
227885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      "// the imported script does nothing"));
228885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  net::URLRequestFilter::GetInstance()->AddUrlInterceptor(
229885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      import_url, interceptor.Pass());
230885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
231885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
232885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgvoid CountScriptResources(
233885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    ServiceWorkerContextWrapper* wrapper,
234885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    const GURL& scope,
235885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    int* num_resources) {
236885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  *num_resources = -1;
237885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
238885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  std::vector<ServiceWorkerRegistrationInfo> infos =
239885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org     wrapper->context()->GetAllLiveRegistrationInfo();
240885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  if (infos.empty())
241885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    return;
242885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
243885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  int version_id;
244885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  size_t index = infos.size() - 1;
245885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  if (!infos[index].installing_version.is_null)
246885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    version_id = infos[index].installing_version.version_id;
247885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  else if (!infos[index].waiting_version.is_null)
248885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    version_id = infos[1].waiting_version.version_id;
249885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  else if (!infos[index].active_version.is_null)
250885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    version_id = infos[index].active_version.version_id;
251885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  else
252885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    return;
253885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
254885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  ServiceWorkerVersion* version =
255885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      wrapper->context()->GetLiveVersion(version_id);
256885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  *num_resources = static_cast<int>(version->script_cache_map()->size());
257885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}
258885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
259885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org}  // namespace
260885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
261885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgclass ServiceWorkerBrowserTest : public ContentBrowserTest {
262885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org protected:
263885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  typedef ServiceWorkerBrowserTest self;
264e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org
265885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  virtual void SetUpCommandLine(base::CommandLine* command_line) OVERRIDE {
266885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    command_line->AppendSwitch(
267885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        switches::kEnableExperimentalWebPlatformFeatures);
268885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  }
269885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
270885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  virtual void SetUpOnMainThread() OVERRIDE {
271885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
272885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    StoragePartition* partition = BrowserContext::GetDefaultStoragePartition(
273885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        shell()->web_contents()->GetBrowserContext());
274885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    wrapper_ = static_cast<ServiceWorkerContextWrapper*>(
275885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        partition->GetServiceWorkerContext());
276885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
277885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    // Navigate to the page to set up a renderer page (where we can embed
278885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    // a worker).
279885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    NavigateToURLBlockUntilNavigationsComplete(
280885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        shell(),
281885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        embedded_test_server()->GetURL("/service_worker/empty.html"), 1);
282885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
283885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    RunOnIOThread(base::Bind(&self::SetUpOnIOThread, this));
284885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  }
2853c3902f0ac13428394f14f78f0fab05ef3468d69tlegrand@google.com
286885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  virtual void TearDownOnMainThread() OVERRIDE {
287885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    RunOnIOThread(base::Bind(&self::TearDownOnIOThread, this));
288885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    wrapper_ = NULL;
289885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  }
290885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
291885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  virtual void SetUpOnIOThread() {}
292885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  virtual void TearDownOnIOThread() {}
293885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
294885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  ServiceWorkerContextWrapper* wrapper() { return wrapper_.get(); }
295885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  ServiceWorkerContext* public_context() { return wrapper(); }
296885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
297885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  void AssociateRendererProcessToPattern(const GURL& pattern) {
298885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    wrapper_->process_manager()->AddProcessReferenceToPattern(
299885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        pattern, shell()->web_contents()->GetRenderProcessHost()->GetID());
300885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  }
301885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
302885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org private:
303885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  scoped_refptr<ServiceWorkerContextWrapper> wrapper_;
304885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org};
305885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
306885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgclass EmbeddedWorkerBrowserTest : public ServiceWorkerBrowserTest,
307885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                                  public EmbeddedWorkerInstance::Listener {
308885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org public:
309885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  typedef EmbeddedWorkerBrowserTest self;
310885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
311885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  EmbeddedWorkerBrowserTest()
312885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      : last_worker_status_(EmbeddedWorkerInstance::STOPPED),
313885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        pause_mode_(DONT_PAUSE) {}
314885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  virtual ~EmbeddedWorkerBrowserTest() {}
315885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
316885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  virtual void TearDownOnIOThread() OVERRIDE {
317885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    if (worker_) {
318885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      worker_->RemoveListener(this);
319885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      worker_.reset();
320885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    }
321885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  }
322885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
323885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  void StartOnIOThread() {
324885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
325885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    worker_ = wrapper()->context()->embedded_worker_registry()->CreateWorker();
326885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker_->status());
327885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    worker_->AddListener(this);
328885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
329885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
330885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    const int64 service_worker_version_id = 33L;
331885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    const GURL pattern = embedded_test_server()->GetURL("/");
332885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    const GURL script_url = embedded_test_server()->GetURL(
333885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        "/service_worker/worker.js");
334885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    AssociateRendererProcessToPattern(pattern);
335885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    int process_id = shell()->web_contents()->GetRenderProcessHost()->GetID();
336885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    wrapper()->process_manager()->AddProcessReferenceToPattern(
337885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        pattern, process_id);
338885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    worker_->Start(
339885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        service_worker_version_id,
340885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        pattern,
341885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        script_url,
342885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        pause_mode_ != DONT_PAUSE,
343885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org        base::Bind(&EmbeddedWorkerBrowserTest::StartOnIOThread2, this));
344885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  }
345885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  void StartOnIOThread2(ServiceWorkerStatusCode status) {
346885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    last_worker_status_ = worker_->status();
347885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    EXPECT_EQ(SERVICE_WORKER_OK, status);
348885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    EXPECT_EQ(EmbeddedWorkerInstance::STARTING, last_worker_status_);
349885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
350885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    if (status != SERVICE_WORKER_OK && !done_closure_.is_null())
351885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      done_closure_.Run();
352885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  }
353885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
354885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  void StopOnIOThread() {
355885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
356885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    EXPECT_EQ(EmbeddedWorkerInstance::RUNNING, worker_->status());
357885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
358885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    ServiceWorkerStatusCode status = worker_->Stop();
359885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
360885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    last_worker_status_ = worker_->status();
361885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    EXPECT_EQ(SERVICE_WORKER_OK, status);
362885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    EXPECT_EQ(EmbeddedWorkerInstance::STOPPING, last_worker_status_);
363885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
364885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    if (status != SERVICE_WORKER_OK && !done_closure_.is_null())
365885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      done_closure_.Run();
366885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  }
367885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
368885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org protected:
369885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  // EmbeddedWorkerInstance::Observer overrides:
370885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  virtual void OnStarted() OVERRIDE {
371885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    ASSERT_TRUE(worker_ != NULL);
372885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    ASSERT_FALSE(done_closure_.is_null());
373885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    last_worker_status_ = worker_->status();
374885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, done_closure_);
375885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  }
376885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  virtual void OnStopped() OVERRIDE {
377885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    ASSERT_TRUE(worker_ != NULL);
378885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    ASSERT_FALSE(done_closure_.is_null());
379885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    last_worker_status_ = worker_->status();
380885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, done_closure_);
381885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  }
382885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  virtual void OnPausedAfterDownload() OVERRIDE {
383885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    if (pause_mode_ == PAUSE_THEN_RESUME)
384885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      worker_->ResumeAfterDownload();
385885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    else if (pause_mode_ == PAUSE_THEN_STOP)
386885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      worker_->Stop();
387885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    else
388885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org      ASSERT_TRUE(false);
389885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  }
390885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  virtual void OnReportException(const base::string16& error_message,
391885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                                 int line_number,
392885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                                 int column_number,
393885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                                 const GURL& source_url) OVERRIDE {}
394885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  virtual void OnReportConsoleMessage(int source_identifier,
395885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                                      int message_level,
396885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                                      const base::string16& message,
397885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                                      int line_number,
398885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                                      const GURL& source_url) OVERRIDE {}
399885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
400885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    return false;
401885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  }
402885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
403885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  scoped_ptr<EmbeddedWorkerInstance> worker_;
404885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  EmbeddedWorkerInstance::Status last_worker_status_;
405885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
406885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  enum {
407885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    DONT_PAUSE,
408885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    PAUSE_THEN_RESUME,
409885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    PAUSE_THEN_STOP,
410885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  } pause_mode_;
411885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
412885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  // Called by EmbeddedWorkerInstance::Observer overrides so that
413885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  // test code can wait for the worker status notifications.
414885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  base::Closure done_closure_;
415885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org};
416885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
417885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.orgclass ServiceWorkerVersionBrowserTest : public ServiceWorkerBrowserTest {
418885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org public:
419885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  typedef ServiceWorkerVersionBrowserTest self;
420885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
421885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  virtual ~ServiceWorkerVersionBrowserTest() {}
422885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
423885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  virtual void TearDownOnIOThread() OVERRIDE {
424885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    registration_ = NULL;
425885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    version_ = NULL;
426885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  }
427885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
428885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org  void InstallTestHelper(const std::string& worker_url,
429885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                         ServiceWorkerStatusCode expected_status) {
430885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread, this,
431885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                             worker_url));
432885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
433885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    // Dispatch install on a worker.
434885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
435885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    base::RunLoop install_run_loop;
436885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
437885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                            base::Bind(&self::InstallOnIOThread, this,
438885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                                       install_run_loop.QuitClosure(),
439885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org                                       &status));
440885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    install_run_loop.Run();
441885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    ASSERT_EQ(expected_status, status);
442885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org
443885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    // Stop the worker.
444e3ea049fcaee2247e45f0ce793d4313babb4ef69tlegrand@chromium.org    status = SERVICE_WORKER_ERROR_FAILED;
445885f2ff5a7a7d6a73432d26a6c0ae9147e6b452sergeyu@chromium.org    base::RunLoop stop_run_loop;
446    BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
447                            base::Bind(&self::StopOnIOThread, this,
448                                       stop_run_loop.QuitClosure(),
449                                       &status));
450    stop_run_loop.Run();
451    ASSERT_EQ(SERVICE_WORKER_OK, status);
452  }
453
454  void ActivateTestHelper(
455      const std::string& worker_url,
456      ServiceWorkerStatusCode expected_status) {
457    RunOnIOThread(
458        base::Bind(&self::SetUpRegistrationOnIOThread, this, worker_url));
459    ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
460    base::RunLoop run_loop;
461    BrowserThread::PostTask(
462        BrowserThread::IO,
463        FROM_HERE,
464        base::Bind(
465            &self::ActivateOnIOThread, this, run_loop.QuitClosure(), &status));
466    run_loop.Run();
467    ASSERT_EQ(expected_status, status);
468  }
469
470  void FetchOnRegisteredWorker(
471      ServiceWorkerFetchEventResult* result,
472      ServiceWorkerResponse* response,
473      scoped_ptr<storage::BlobDataHandle>* blob_data_handle) {
474    blob_context_ = ChromeBlobStorageContext::GetFor(
475        shell()->web_contents()->GetBrowserContext());
476    bool prepare_result = false;
477    FetchResult fetch_result;
478    fetch_result.status = SERVICE_WORKER_ERROR_FAILED;
479    base::RunLoop fetch_run_loop;
480    BrowserThread::PostTask(BrowserThread::IO,
481                            FROM_HERE,
482                            base::Bind(&self::FetchOnIOThread,
483                                       this,
484                                       fetch_run_loop.QuitClosure(),
485                                       &prepare_result,
486                                       &fetch_result));
487    fetch_run_loop.Run();
488    ASSERT_TRUE(prepare_result);
489    *result = fetch_result.result;
490    *response = fetch_result.response;
491    *blob_data_handle = fetch_result.blob_data_handle.Pass();
492    ASSERT_EQ(SERVICE_WORKER_OK, fetch_result.status);
493  }
494
495  void FetchTestHelper(const std::string& worker_url,
496                       ServiceWorkerFetchEventResult* result,
497                       ServiceWorkerResponse* response,
498                       scoped_ptr<storage::BlobDataHandle>* blob_data_handle) {
499    RunOnIOThread(
500        base::Bind(&self::SetUpRegistrationOnIOThread, this, worker_url));
501    FetchOnRegisteredWorker(result, response, blob_data_handle);
502  }
503
504  void SetUpRegistrationOnIOThread(const std::string& worker_url) {
505    const GURL pattern = embedded_test_server()->GetURL("/");
506    registration_ = new ServiceWorkerRegistration(
507        pattern,
508        wrapper()->context()->storage()->NewRegistrationId(),
509        wrapper()->context()->AsWeakPtr());
510    version_ = new ServiceWorkerVersion(
511        registration_.get(),
512        embedded_test_server()->GetURL(worker_url),
513        wrapper()->context()->storage()->NewVersionId(),
514        wrapper()->context()->AsWeakPtr());
515    AssociateRendererProcessToPattern(pattern);
516  }
517
518  void StartOnIOThread(const base::Closure& done,
519                       ServiceWorkerStatusCode* result) {
520    ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
521    version_->StartWorker(CreateReceiver(BrowserThread::UI, done, result));
522  }
523
524  void InstallOnIOThread(const base::Closure& done,
525                         ServiceWorkerStatusCode* result) {
526    ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
527    version_->SetStatus(ServiceWorkerVersion::INSTALLING);
528    version_->DispatchInstallEvent(
529        -1, CreateReceiver(BrowserThread::UI, done, result));
530  }
531
532  void ActivateOnIOThread(const base::Closure& done,
533                          ServiceWorkerStatusCode* result) {
534    ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
535    version_->SetStatus(ServiceWorkerVersion::ACTIVATING);
536    version_->DispatchActivateEvent(
537        CreateReceiver(BrowserThread::UI, done, result));
538  }
539
540  void FetchOnIOThread(const base::Closure& done,
541                       bool* prepare_result,
542                       FetchResult* result) {
543    ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
544    ServiceWorkerFetchRequest request(
545        embedded_test_server()->GetURL("/service_worker/empty.html"),
546        "GET",
547        ServiceWorkerHeaderMap(),
548        GURL(""),
549        false);
550    version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
551    version_->DispatchFetchEvent(
552        request,
553        CreatePrepareReceiver(prepare_result),
554        CreateResponseReceiver(
555            BrowserThread::UI, done, blob_context_.get(), result));
556  }
557
558  void StopOnIOThread(const base::Closure& done,
559                      ServiceWorkerStatusCode* result) {
560    ASSERT_TRUE(version_.get());
561    version_->StopWorker(CreateReceiver(BrowserThread::UI, done, result));
562  }
563
564  void SyncEventOnIOThread(const base::Closure& done,
565                           ServiceWorkerStatusCode* result) {
566    ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
567    version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
568    version_->DispatchSyncEvent(
569        CreateReceiver(BrowserThread::UI, done, result));
570  }
571
572 protected:
573  scoped_refptr<ServiceWorkerRegistration> registration_;
574  scoped_refptr<ServiceWorkerVersion> version_;
575  scoped_refptr<ChromeBlobStorageContext> blob_context_;
576};
577
578IN_PROC_BROWSER_TEST_F(EmbeddedWorkerBrowserTest, StartAndStop) {
579  // Start a worker and wait until OnStarted() is called.
580  base::RunLoop start_run_loop;
581  done_closure_ = start_run_loop.QuitClosure();
582  BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
583                          base::Bind(&self::StartOnIOThread, this));
584  start_run_loop.Run();
585
586  ASSERT_EQ(EmbeddedWorkerInstance::RUNNING, last_worker_status_);
587
588  // Stop a worker and wait until OnStopped() is called.
589  base::RunLoop stop_run_loop;
590  done_closure_ = stop_run_loop.QuitClosure();
591  BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
592                          base::Bind(&self::StopOnIOThread, this));
593  stop_run_loop.Run();
594
595  ASSERT_EQ(EmbeddedWorkerInstance::STOPPED, last_worker_status_);
596}
597
598IN_PROC_BROWSER_TEST_F(EmbeddedWorkerBrowserTest, StartPaused_ThenResume) {
599  pause_mode_ = PAUSE_THEN_RESUME;
600  base::RunLoop start_run_loop;
601  done_closure_ = start_run_loop.QuitClosure();
602  BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
603                          base::Bind(&self::StartOnIOThread, this));
604  start_run_loop.Run();
605  ASSERT_EQ(EmbeddedWorkerInstance::RUNNING, last_worker_status_);
606}
607
608IN_PROC_BROWSER_TEST_F(EmbeddedWorkerBrowserTest,
609                       StartPaused_ThenStop) {
610  pause_mode_ = PAUSE_THEN_STOP;
611  base::RunLoop start_run_loop;
612  done_closure_ = start_run_loop.QuitClosure();
613  BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
614                          base::Bind(&self::StartOnIOThread, this));
615  start_run_loop.Run();
616  ASSERT_EQ(EmbeddedWorkerInstance::STOPPED, last_worker_status_);
617}
618
619IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, StartAndStop) {
620  RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread, this,
621                           "/service_worker/worker.js"));
622
623  // Start a worker.
624  ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
625  base::RunLoop start_run_loop;
626  BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
627                          base::Bind(&self::StartOnIOThread, this,
628                                     start_run_loop.QuitClosure(),
629                                     &status));
630  start_run_loop.Run();
631  ASSERT_EQ(SERVICE_WORKER_OK, status);
632
633  // Stop the worker.
634  status = SERVICE_WORKER_ERROR_FAILED;
635  base::RunLoop stop_run_loop;
636  BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
637                          base::Bind(&self::StopOnIOThread, this,
638                                     stop_run_loop.QuitClosure(),
639                                     &status));
640  stop_run_loop.Run();
641  ASSERT_EQ(SERVICE_WORKER_OK, status);
642}
643
644IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, StartNotFound) {
645  RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread, this,
646                           "/service_worker/nonexistent.js"));
647
648  // Start a worker for nonexistent URL.
649  ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
650  base::RunLoop start_run_loop;
651  BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
652                          base::Bind(&self::StartOnIOThread, this,
653                                     start_run_loop.QuitClosure(),
654                                     &status));
655  start_run_loop.Run();
656  ASSERT_EQ(SERVICE_WORKER_ERROR_START_WORKER_FAILED, status);
657}
658
659IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, Install) {
660  InstallTestHelper("/service_worker/worker.js", SERVICE_WORKER_OK);
661}
662
663IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
664                       InstallWithWaitUntil_Fulfilled) {
665  InstallTestHelper("/service_worker/worker_install_fulfilled.js",
666                    SERVICE_WORKER_OK);
667}
668
669// Check that ServiceWorker script requests set a "Service-Worker: script"
670// header.
671IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
672                       ServiceWorkerScriptHeader) {
673  embedded_test_server()->RegisterRequestHandler(
674      base::Bind(&VerifyServiceWorkerHeaderInRequest));
675  InstallTestHelper("/service_worker/generated_sw.js", SERVICE_WORKER_OK);
676}
677
678IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
679                       Activate_NoEventListener) {
680  ActivateTestHelper("/service_worker/worker.js", SERVICE_WORKER_OK);
681  ASSERT_EQ(ServiceWorkerVersion::ACTIVATING, version_->status());
682}
683
684IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, Activate_Rejected) {
685  ActivateTestHelper("/service_worker/worker_activate_rejected.js",
686                     SERVICE_WORKER_ERROR_ACTIVATE_WORKER_FAILED);
687}
688
689IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
690                       InstallWithWaitUntil_Rejected) {
691  InstallTestHelper("/service_worker/worker_install_rejected.js",
692                    SERVICE_WORKER_ERROR_INSTALL_WORKER_FAILED);
693}
694
695IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, FetchEvent_Response) {
696  ServiceWorkerFetchEventResult result;
697  ServiceWorkerResponse response;
698  scoped_ptr<storage::BlobDataHandle> blob_data_handle;
699  FetchTestHelper("/service_worker/fetch_event.js",
700                  &result, &response, &blob_data_handle);
701  ASSERT_EQ(SERVICE_WORKER_FETCH_EVENT_RESULT_RESPONSE, result);
702  EXPECT_EQ(301, response.status_code);
703  EXPECT_EQ("Moved Permanently", response.status_text);
704  ServiceWorkerHeaderMap expected_headers;
705  expected_headers["content-language"] = "fi";
706  expected_headers["content-type"] = "text/html; charset=UTF-8";
707  EXPECT_EQ(expected_headers, response.headers);
708
709  std::string body;
710  RunOnIOThread(
711      base::Bind(&ReadResponseBody,
712                 &body, base::Owned(blob_data_handle.release())));
713  EXPECT_EQ("This resource is gone. Gone, gone, gone.", body);
714}
715
716IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
717                       SyncAbortedWithoutFlag) {
718  RunOnIOThread(base::Bind(
719      &self::SetUpRegistrationOnIOThread, this, "/service_worker/sync.js"));
720
721  // Run the sync event.
722  ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
723  base::RunLoop sync_run_loop;
724  BrowserThread::PostTask(BrowserThread::IO,
725                          FROM_HERE,
726                          base::Bind(&self::SyncEventOnIOThread,
727                                     this,
728                                     sync_run_loop.QuitClosure(),
729                                     &status));
730  sync_run_loop.Run();
731  ASSERT_EQ(SERVICE_WORKER_ERROR_ABORT, status);
732}
733
734IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, SyncEventHandled) {
735  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
736  command_line->AppendSwitch(switches::kEnableServiceWorkerSync);
737
738  RunOnIOThread(base::Bind(
739      &self::SetUpRegistrationOnIOThread, this, "/service_worker/sync.js"));
740  ServiceWorkerFetchEventResult result;
741  ServiceWorkerResponse response;
742  scoped_ptr<storage::BlobDataHandle> blob_data_handle;
743  // Should 404 before sync event.
744  FetchOnRegisteredWorker(&result, &response, &blob_data_handle);
745  EXPECT_EQ(404, response.status_code);
746
747  // Run the sync event.
748  ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
749  base::RunLoop sync_run_loop;
750  BrowserThread::PostTask(BrowserThread::IO,
751                          FROM_HERE,
752                          base::Bind(&self::SyncEventOnIOThread,
753                                     this,
754                                     sync_run_loop.QuitClosure(),
755                                     &status));
756  sync_run_loop.Run();
757  ASSERT_EQ(SERVICE_WORKER_OK, status);
758
759  // Should 200 after sync event.
760  FetchOnRegisteredWorker(&result, &response, &blob_data_handle);
761  EXPECT_EQ(200, response.status_code);
762}
763
764// ServiceWorkerBrowserTest.Reload is flaky on Android crbug.com/393486
765#if defined(OS_ANDROID)
766#define MAYBE_Reload DISABLED_Reload
767#else
768#define MAYBE_Reload Reload
769#endif
770IN_PROC_BROWSER_TEST_F(ServiceWorkerBrowserTest, MAYBE_Reload) {
771  const std::string kPageUrl = "/service_worker/reload.html";
772  const std::string kWorkerUrl = "/service_worker/fetch_event_reload.js";
773  {
774    scoped_refptr<WorkerActivatedObserver> observer =
775        new WorkerActivatedObserver(wrapper());
776    observer->Init();
777    public_context()->RegisterServiceWorker(
778        embedded_test_server()->GetURL(kPageUrl),
779        embedded_test_server()->GetURL(kWorkerUrl),
780        base::Bind(&ExpectResultAndRun, true, base::Bind(&base::DoNothing)));
781    observer->Wait();
782  }
783  {
784    const base::string16 title = base::ASCIIToUTF16("reload=false");
785    TitleWatcher title_watcher(shell()->web_contents(), title);
786    NavigateToURL(shell(), embedded_test_server()->GetURL(kPageUrl));
787    EXPECT_EQ(title, title_watcher.WaitAndGetTitle());
788  }
789  {
790    const base::string16 title = base::ASCIIToUTF16("reload=true");
791    TitleWatcher title_watcher(shell()->web_contents(), title);
792    ReloadBlockUntilNavigationsComplete(shell(), 1);
793    EXPECT_EQ(title, title_watcher.WaitAndGetTitle());
794  }
795  shell()->Close();
796  {
797    base::RunLoop run_loop;
798    public_context()->UnregisterServiceWorker(
799        embedded_test_server()->GetURL(kPageUrl),
800        base::Bind(&ExpectResultAndRun, true, run_loop.QuitClosure()));
801    run_loop.Run();
802  }
803}
804
805IN_PROC_BROWSER_TEST_F(ServiceWorkerBrowserTest, ImportsBustMemcache) {
806  const std::string kScopeUrl = "/service_worker/imports_bust_memcache_scope/";
807  const std::string kPageUrl = "/service_worker/imports_bust_memcache.html";
808  const std::string kScriptUrl = "/service_worker/worker_with_one_import.js";
809  const std::string kImportUrl = "/service_worker/long_lived_import.js";
810  const base::string16 kOKTitle(base::ASCIIToUTF16("OK"));
811  const base::string16 kFailTitle(base::ASCIIToUTF16("FAIL"));
812
813  RunOnIOThread(
814      base::Bind(&CreateLongLivedResourceInterceptors,
815                 embedded_test_server()->GetURL(kScriptUrl),
816                 embedded_test_server()->GetURL(kImportUrl)));
817
818  TitleWatcher title_watcher(shell()->web_contents(), kOKTitle);
819  title_watcher.AlsoWaitForTitle(kFailTitle);
820  NavigateToURL(shell(), embedded_test_server()->GetURL(kPageUrl));
821  base::string16 title = title_watcher.WaitAndGetTitle();
822  EXPECT_EQ(kOKTitle, title);
823
824  // Verify the number of resources in the implicit script cache is correct.
825  const int kExpectedNumResources = 2;
826  int num_resources = 0;
827  RunOnIOThread(
828      base::Bind(&CountScriptResources,
829                 base::Unretained(wrapper()),
830                 embedded_test_server()->GetURL(kScopeUrl),
831                 &num_resources));
832  EXPECT_EQ(kExpectedNumResources, num_resources);
833}
834
835class ServiceWorkerBlackBoxBrowserTest : public ServiceWorkerBrowserTest {
836 public:
837  typedef ServiceWorkerBlackBoxBrowserTest self;
838
839  void FindRegistrationOnIO(const GURL& document_url,
840                            ServiceWorkerStatusCode* status,
841                            const base::Closure& continuation) {
842    wrapper()->context()->storage()->FindRegistrationForDocument(
843        document_url,
844        base::Bind(&ServiceWorkerBlackBoxBrowserTest::FindRegistrationOnIO2,
845                   this,
846                   status,
847                   continuation));
848  }
849
850  void FindRegistrationOnIO2(
851      ServiceWorkerStatusCode* out_status,
852      const base::Closure& continuation,
853      ServiceWorkerStatusCode status,
854      const scoped_refptr<ServiceWorkerRegistration>& registration) {
855    *out_status = status;
856    if (!registration.get())
857      EXPECT_NE(SERVICE_WORKER_OK, status);
858    continuation.Run();
859  }
860};
861
862static int CountRenderProcessHosts() {
863  int result = 0;
864  for (RenderProcessHost::iterator iter(RenderProcessHost::AllHostsIterator());
865       !iter.IsAtEnd();
866       iter.Advance()) {
867    result++;
868  }
869  return result;
870}
871
872// Crashes on Android and flakes on CrOS: http://crbug.com/387045
873#if defined(OS_ANDROID) || defined(OS_CHROMEOS)
874#define MAYBE_Registration DISABLED_Registration
875#else
876#define MAYBE_Registration Registration
877#endif
878IN_PROC_BROWSER_TEST_F(ServiceWorkerBlackBoxBrowserTest, MAYBE_Registration) {
879  // Close the only window to be sure we're not re-using its RenderProcessHost.
880  shell()->Close();
881  EXPECT_EQ(0, CountRenderProcessHosts());
882
883  const std::string kWorkerUrl = "/service_worker/fetch_event.js";
884
885  // Unregistering nothing should return false.
886  {
887    base::RunLoop run_loop;
888    public_context()->UnregisterServiceWorker(
889        embedded_test_server()->GetURL("/"),
890        base::Bind(&ExpectResultAndRun, false, run_loop.QuitClosure()));
891    run_loop.Run();
892  }
893
894  // If we use a worker URL that doesn't exist, registration fails.
895  {
896    base::RunLoop run_loop;
897    public_context()->RegisterServiceWorker(
898        embedded_test_server()->GetURL("/"),
899        embedded_test_server()->GetURL("/does/not/exist"),
900        base::Bind(&ExpectResultAndRun, false, run_loop.QuitClosure()));
901    run_loop.Run();
902  }
903  EXPECT_EQ(0, CountRenderProcessHosts());
904
905  // Register returns when the promise would be resolved.
906  {
907    base::RunLoop run_loop;
908    public_context()->RegisterServiceWorker(
909        embedded_test_server()->GetURL("/"),
910        embedded_test_server()->GetURL(kWorkerUrl),
911        base::Bind(&ExpectResultAndRun, true, run_loop.QuitClosure()));
912    run_loop.Run();
913  }
914  EXPECT_EQ(1, CountRenderProcessHosts());
915
916  // Registering again should succeed, although the algo still
917  // might not be complete.
918  {
919    base::RunLoop run_loop;
920    public_context()->RegisterServiceWorker(
921        embedded_test_server()->GetURL("/"),
922        embedded_test_server()->GetURL(kWorkerUrl),
923        base::Bind(&ExpectResultAndRun, true, run_loop.QuitClosure()));
924    run_loop.Run();
925  }
926
927  // The registration algo might not be far enough along to have
928  // stored the registration data, so it may not be findable
929  // at this point.
930
931  // Unregistering something should return true.
932  {
933    base::RunLoop run_loop;
934    public_context()->UnregisterServiceWorker(
935        embedded_test_server()->GetURL("/"),
936        base::Bind(&ExpectResultAndRun, true, run_loop.QuitClosure()));
937    run_loop.Run();
938  }
939  EXPECT_GE(1, CountRenderProcessHosts()) << "Unregistering doesn't stop the "
940                                             "workers eagerly, so their RPHs "
941                                             "can still be running.";
942
943  // Should not be able to find it.
944  {
945    ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
946    RunOnIOThread(
947        base::Bind(&ServiceWorkerBlackBoxBrowserTest::FindRegistrationOnIO,
948                   this,
949                   embedded_test_server()->GetURL("/service_worker/empty.html"),
950                   &status));
951    EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND, status);
952  }
953}
954
955}  // namespace content
956