1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/files/scoped_temp_dir.h"
6#include "base/logging.h"
7#include "base/run_loop.h"
8#include "content/browser/browser_thread_impl.h"
9#include "content/browser/fileapi/mock_url_request_delegate.h"
10#include "content/browser/service_worker/embedded_worker_test_helper.h"
11#include "content/browser/service_worker/service_worker_context_core.h"
12#include "content/browser/service_worker/service_worker_controllee_request_handler.h"
13#include "content/browser/service_worker/service_worker_provider_host.h"
14#include "content/browser/service_worker/service_worker_registration.h"
15#include "content/browser/service_worker/service_worker_registration.h"
16#include "content/browser/service_worker/service_worker_url_request_job.h"
17#include "content/browser/service_worker/service_worker_utils.h"
18#include "content/common/resource_request_body.h"
19#include "content/public/test/test_browser_thread_bundle.h"
20#include "net/url_request/url_request_context.h"
21#include "testing/gtest/include/gtest/gtest.h"
22
23namespace content {
24
25namespace {
26
27int kMockRenderProcessId = 1224;
28int kMockProviderId = 1;
29
30void EmptyCallback() {}
31
32}
33
34class ServiceWorkerControlleeRequestHandlerTest : public testing::Test {
35 public:
36  ServiceWorkerControlleeRequestHandlerTest()
37      : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {}
38
39  virtual void SetUp() OVERRIDE {
40    helper_.reset(new EmbeddedWorkerTestHelper(kMockRenderProcessId));
41
42    // A new unstored registration/version.
43    scope_ = GURL("http://host/scope/");
44    script_url_ = GURL("http://host/script.js");
45    registration_ = new ServiceWorkerRegistration(
46        scope_, 1L, context()->AsWeakPtr());
47    version_ = new ServiceWorkerVersion(
48        registration_.get(), script_url_, 1L, context()->AsWeakPtr());
49
50    // An empty host.
51    scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
52        kMockRenderProcessId, kMockProviderId,
53        context()->AsWeakPtr(), NULL));
54    provider_host_ = host->AsWeakPtr();
55    context()->AddProviderHost(host.Pass());
56
57    context()->storage()->LazyInitialize(base::Bind(&EmptyCallback));
58    base::RunLoop().RunUntilIdle();
59  }
60
61  virtual void TearDown() OVERRIDE {
62    version_ = NULL;
63    registration_ = NULL;
64    helper_.reset();
65  }
66
67  ServiceWorkerContextCore* context() const { return helper_->context(); }
68
69 protected:
70  TestBrowserThreadBundle browser_thread_bundle_;
71  scoped_ptr<EmbeddedWorkerTestHelper> helper_;
72  scoped_refptr<ServiceWorkerRegistration> registration_;
73  scoped_refptr<ServiceWorkerVersion> version_;
74  base::WeakPtr<ServiceWorkerProviderHost> provider_host_;
75  net::URLRequestContext url_request_context_;
76  MockURLRequestDelegate url_request_delegate_;
77  GURL scope_;
78  GURL script_url_;
79};
80
81TEST_F(ServiceWorkerControlleeRequestHandlerTest, ActivateWaitingVersion) {
82  // Store a registration that is installed but not activated yet.
83  version_->SetStatus(ServiceWorkerVersion::INSTALLED);
84  registration_->SetWaitingVersion(version_.get());
85  context()->storage()->StoreRegistration(
86      registration_.get(),
87      version_.get(),
88      base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
89  base::RunLoop().RunUntilIdle();
90
91  // Conduct a main resource load.
92  const GURL kDocUrl("http://host/scope/doc");
93  scoped_ptr<net::URLRequest> request = url_request_context_.CreateRequest(
94      kDocUrl,
95      net::DEFAULT_PRIORITY,
96      &url_request_delegate_,
97      NULL);
98  scoped_ptr<ServiceWorkerControlleeRequestHandler> handler(
99      new ServiceWorkerControlleeRequestHandler(
100          context()->AsWeakPtr(),
101          provider_host_,
102          base::WeakPtr<storage::BlobStorageContext>(),
103          RESOURCE_TYPE_MAIN_FRAME,
104          scoped_refptr<ResourceRequestBody>()));
105  scoped_refptr<net::URLRequestJob> job =
106      handler->MaybeCreateJob(request.get(), NULL);
107  ServiceWorkerURLRequestJob* sw_job =
108      static_cast<ServiceWorkerURLRequestJob*>(job.get());
109
110  EXPECT_FALSE(sw_job->ShouldFallbackToNetwork());
111  EXPECT_FALSE(sw_job->ShouldForwardToServiceWorker());
112  EXPECT_FALSE(version_->HasControllee());
113
114  base::RunLoop().RunUntilIdle();
115
116  EXPECT_EQ(ServiceWorkerVersion::ACTIVATED,
117            version_->status());
118  EXPECT_FALSE(sw_job->ShouldFallbackToNetwork());
119  EXPECT_TRUE(sw_job->ShouldForwardToServiceWorker());
120  EXPECT_TRUE(version_->HasControllee());
121
122  // Navigations should trigger an update too.
123  handler.reset(NULL);
124  EXPECT_TRUE(version_->update_timer_.IsRunning());
125}
126
127// Test to not regress crbug/414118.
128TEST_F(ServiceWorkerControlleeRequestHandlerTest, DeletedProviderHost) {
129  // Store a registration so the call to FindRegistrationForDocument will read
130  // from the database.
131  version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
132  registration_->SetActiveVersion(version_.get());
133  context()->storage()->StoreRegistration(
134      registration_.get(),
135      version_.get(),
136      base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
137  base::RunLoop().RunUntilIdle();
138  version_ = NULL;
139  registration_ = NULL;
140
141  // Conduct a main resource load.
142  const GURL kDocUrl("http://host/scope/doc");
143  scoped_ptr<net::URLRequest> request = url_request_context_.CreateRequest(
144      kDocUrl,
145      net::DEFAULT_PRIORITY,
146      &url_request_delegate_,
147      NULL);
148  scoped_ptr<ServiceWorkerControlleeRequestHandler> handler(
149      new ServiceWorkerControlleeRequestHandler(
150          context()->AsWeakPtr(),
151          provider_host_,
152          base::WeakPtr<storage::BlobStorageContext>(),
153          RESOURCE_TYPE_MAIN_FRAME,
154          scoped_refptr<ResourceRequestBody>()));
155  scoped_refptr<net::URLRequestJob> job =
156      handler->MaybeCreateJob(request.get(), NULL);
157  ServiceWorkerURLRequestJob* sw_job =
158      static_cast<ServiceWorkerURLRequestJob*>(job.get());
159
160  EXPECT_FALSE(sw_job->ShouldFallbackToNetwork());
161  EXPECT_FALSE(sw_job->ShouldForwardToServiceWorker());
162
163  // Shouldn't crash if the ProviderHost is deleted prior to completion of
164  // the database lookup.
165  context()->RemoveProviderHost(kMockRenderProcessId, kMockProviderId);
166  EXPECT_FALSE(provider_host_.get());
167  base::RunLoop().RunUntilIdle();
168  EXPECT_TRUE(sw_job->ShouldFallbackToNetwork());
169  EXPECT_FALSE(sw_job->ShouldForwardToServiceWorker());
170}
171
172}  // namespace content
173