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 <stdint.h>
6 #include <tuple>
7
8 #include "base/barrier_closure.h"
9 #include "base/bind.h"
10 #include "base/callback_helpers.h"
11 #include "base/check.h"
12 #include "base/files/scoped_temp_dir.h"
13 #include "base/optional.h"
14 #include "base/run_loop.h"
15 #include "base/stl_util.h"
16 #include "base/test/bind.h"
17 #include "base/test/metrics/histogram_tester.h"
18 #include "base/test/scoped_feature_list.h"
19 #include "base/test/test_simple_task_runner.h"
20 #include "base/time/time.h"
21 #include "content/browser/renderer_host/frame_tree_node.h"
22 #include "content/browser/service_worker/embedded_worker_status.h"
23 #include "content/browser/service_worker/embedded_worker_test_helper.h"
24 #include "content/browser/service_worker/fake_embedded_worker_instance_client.h"
25 #include "content/browser/service_worker/service_worker_consts.h"
26 #include "content/browser/service_worker/service_worker_container_host.h"
27 #include "content/browser/service_worker/service_worker_context_core.h"
28 #include "content/browser/service_worker/service_worker_context_wrapper.h"
29 #include "content/browser/service_worker/service_worker_job_coordinator.h"
30 #include "content/browser/service_worker/service_worker_object_host.h"
31 #include "content/browser/service_worker/service_worker_registration.h"
32 #include "content/browser/service_worker/service_worker_registration_object_host.h"
33 #include "content/browser/service_worker/service_worker_registration_status.h"
34 #include "content/browser/service_worker/service_worker_test_utils.h"
35 #include "content/browser/service_worker/test_service_worker_observer.h"
36 #include "content/browser/storage_partition_impl.h"
37 #include "content/public/test/browser_task_environment.h"
38 #include "content/public/test/test_browser_context.h"
39 #include "content/public/test/url_loader_interceptor.h"
40 #include "content/test/fake_network.h"
41 #include "ipc/ipc_test_sink.h"
42 #include "net/base/io_buffer.h"
43 #include "net/base/net_errors.h"
44 #include "net/base/test_completion_callback.h"
45 #include "net/http/http_response_headers.h"
46 #include "services/network/public/cpp/features.h"
47 #include "testing/gtest/include/gtest/gtest.h"
48 #include "third_party/blink/public/common/features.h"
49 #include "third_party/blink/public/mojom/service_worker/service_worker.mojom.h"
50 #include "third_party/blink/public/mojom/service_worker/service_worker_event_status.mojom.h"
51 #include "third_party/blink/public/mojom/service_worker/service_worker_object.mojom.h"
52 #include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom.h"
53
54 using net::IOBuffer;
55 using net::TestCompletionCallback;
56 using net::WrappedIOBuffer;
57
58 // Unit tests for testing all job registration tasks.
59 namespace content {
60
61 namespace {
62
SaveRegistrationCallback(blink::ServiceWorkerStatusCode expected_status,scoped_refptr<ServiceWorkerRegistration> * registration_out,base::OnceClosure quit_closure,blink::ServiceWorkerStatusCode status,const std::string & status_message,ServiceWorkerRegistration * registration)63 void SaveRegistrationCallback(
64 blink::ServiceWorkerStatusCode expected_status,
65 scoped_refptr<ServiceWorkerRegistration>* registration_out,
66 base::OnceClosure quit_closure,
67 blink::ServiceWorkerStatusCode status,
68 const std::string& status_message,
69 ServiceWorkerRegistration* registration) {
70 EXPECT_EQ(expected_status, status);
71 *registration_out = registration;
72 std::move(quit_closure).Run();
73 }
74
SaveFoundRegistrationCallback(blink::ServiceWorkerStatusCode expected_status,scoped_refptr<ServiceWorkerRegistration> * registration,base::OnceClosure quit_closure,blink::ServiceWorkerStatusCode status,scoped_refptr<ServiceWorkerRegistration> result)75 void SaveFoundRegistrationCallback(
76 blink::ServiceWorkerStatusCode expected_status,
77 scoped_refptr<ServiceWorkerRegistration>* registration,
78 base::OnceClosure quit_closure,
79 blink::ServiceWorkerStatusCode status,
80 scoped_refptr<ServiceWorkerRegistration> result) {
81 EXPECT_EQ(expected_status, status);
82 *registration = std::move(result);
83 std::move(quit_closure).Run();
84 }
85
86 // Creates a callback which keeps track of the resulting registration.
87 // When the callback is fired, it ensures that the resulting status
88 // matches the expectation.
SaveRegistration(blink::ServiceWorkerStatusCode expected_status,scoped_refptr<ServiceWorkerRegistration> * registration,base::OnceClosure quit_closure)89 ServiceWorkerRegisterJob::RegistrationCallback SaveRegistration(
90 blink::ServiceWorkerStatusCode expected_status,
91 scoped_refptr<ServiceWorkerRegistration>* registration,
92 base::OnceClosure quit_closure) {
93 return base::BindOnce(&SaveRegistrationCallback, expected_status,
94 registration, std::move(quit_closure));
95 }
96
SaveFoundRegistration(blink::ServiceWorkerStatusCode expected_status,scoped_refptr<ServiceWorkerRegistration> * registration,base::OnceClosure quit_closure)97 ServiceWorkerRegistry::FindRegistrationCallback SaveFoundRegistration(
98 blink::ServiceWorkerStatusCode expected_status,
99 scoped_refptr<ServiceWorkerRegistration>* registration,
100 base::OnceClosure quit_closure) {
101 return base::BindOnce(&SaveFoundRegistrationCallback, expected_status,
102 registration, std::move(quit_closure));
103 }
104
SaveUnregistrationCallback(blink::ServiceWorkerStatusCode expected_status,base::OnceClosure quit_closure,int64_t registration_id,blink::ServiceWorkerStatusCode status)105 void SaveUnregistrationCallback(blink::ServiceWorkerStatusCode expected_status,
106 base::OnceClosure quit_closure,
107 int64_t registration_id,
108 blink::ServiceWorkerStatusCode status) {
109 EXPECT_EQ(expected_status, status);
110 std::move(quit_closure).Run();
111 }
112
SaveUnregistration(blink::ServiceWorkerStatusCode expected_status,base::OnceClosure quit_closure)113 ServiceWorkerUnregisterJob::UnregistrationCallback SaveUnregistration(
114 blink::ServiceWorkerStatusCode expected_status,
115 base::OnceClosure quit_closure) {
116 return base::BindOnce(&SaveUnregistrationCallback, expected_status,
117 std::move(quit_closure));
118 }
119
RequestTermination(mojo::AssociatedRemote<blink::mojom::EmbeddedWorkerInstanceHost> * host)120 void RequestTermination(
121 mojo::AssociatedRemote<blink::mojom::EmbeddedWorkerInstanceHost>* host) {
122 // We can't wait for the callback since StopWorker() arrives before it which
123 // severs the Mojo connection.
124 (*host)->RequestTermination(base::DoNothing());
125 }
126
127 class EmbeddedWorkerStatusObserver : public ServiceWorkerVersion::Observer {
128 public:
EmbeddedWorkerStatusObserver(base::OnceClosure quit_closure,EmbeddedWorkerStatus running_status)129 EmbeddedWorkerStatusObserver(base::OnceClosure quit_closure,
130 EmbeddedWorkerStatus running_status)
131 : quit_closure_(std::move(quit_closure)),
132 expected_running_status_(running_status) {}
133
OnRunningStateChanged(ServiceWorkerVersion * version)134 void OnRunningStateChanged(ServiceWorkerVersion* version) override {
135 if (!quit_closure_)
136 return;
137
138 if (version->running_status() == expected_running_status_)
139 std::move(quit_closure_).Run();
140 }
141
142 private:
143 EmbeddedWorkerStatusObserver(const EmbeddedWorkerStatusObserver&) = delete;
144 EmbeddedWorkerStatusObserver& operator=(const EmbeddedWorkerStatusObserver&) =
145 delete;
146
147 base::OnceClosure quit_closure_;
148
149 EmbeddedWorkerStatus expected_running_status_;
150 };
151
CrossOriginEmbedderPolicyNone()152 network::CrossOriginEmbedderPolicy CrossOriginEmbedderPolicyNone() {
153 return network::CrossOriginEmbedderPolicy();
154 }
155
CrossOriginEmbedderPolicyRequireCorp()156 network::CrossOriginEmbedderPolicy CrossOriginEmbedderPolicyRequireCorp() {
157 network::CrossOriginEmbedderPolicy out;
158 out.value = network::mojom::CrossOriginEmbedderPolicyValue::kRequireCorp;
159 return out;
160 }
161
162 } // namespace
163
164 class ServiceWorkerJobTest : public testing::Test {
165 public:
ServiceWorkerJobTest()166 ServiceWorkerJobTest()
167 : task_environment_(base::test::TaskEnvironment::TimeSource::MOCK_TIME,
168 BrowserTaskEnvironment::IO_MAINLOOP) {}
169
SetUp()170 void SetUp() override {
171 helper_.reset(new EmbeddedWorkerTestHelper(base::FilePath()));
172 }
173
TearDown()174 void TearDown() override { helper_.reset(); }
175
context() const176 ServiceWorkerContextCore* context() const { return helper_->context(); }
177
job_coordinator() const178 ServiceWorkerJobCoordinator* job_coordinator() const {
179 return context()->job_coordinator();
180 }
registry() const181 ServiceWorkerRegistry* registry() const { return context()->registry(); }
182
183 protected:
184 scoped_refptr<ServiceWorkerRegistration> RunRegisterJob(
185 const GURL& script_url,
186 const blink::mojom::ServiceWorkerRegistrationOptions& options,
187 blink::ServiceWorkerStatusCode expected_status =
188 blink::ServiceWorkerStatusCode::kOk);
189 void RunUnregisterJob(const GURL& scope,
190 blink::ServiceWorkerStatusCode expected_status =
191 blink::ServiceWorkerStatusCode::kOk);
192 void WaitForVersionRunningStatus(scoped_refptr<ServiceWorkerVersion> version,
193 EmbeddedWorkerStatus running_status);
194 scoped_refptr<ServiceWorkerRegistration> FindRegistrationForScope(
195 const GURL& scope,
196 blink::ServiceWorkerStatusCode expected_status =
197 blink::ServiceWorkerStatusCode::kOk);
198 ServiceWorkerContainerHost* CreateControllee();
199 scoped_refptr<ServiceWorkerRegistration> CreateRegistrationWithControllee(
200 const GURL& script_url,
201 const GURL& scope_url);
202
203 BrowserTaskEnvironment task_environment_;
204 std::unique_ptr<EmbeddedWorkerTestHelper> helper_;
205 std::vector<ServiceWorkerRemoteContainerEndpoint> remote_endpoints_;
206 };
207
RunRegisterJob(const GURL & script_url,const blink::mojom::ServiceWorkerRegistrationOptions & options,blink::ServiceWorkerStatusCode expected_status)208 scoped_refptr<ServiceWorkerRegistration> ServiceWorkerJobTest::RunRegisterJob(
209 const GURL& script_url,
210 const blink::mojom::ServiceWorkerRegistrationOptions& options,
211 blink::ServiceWorkerStatusCode expected_status) {
212 scoped_refptr<ServiceWorkerRegistration> registration;
213 base::RunLoop run_loop;
214 auto outside_fetch_client_settings_object =
215 blink::mojom::FetchClientSettingsObject::New();
216 outside_fetch_client_settings_object->outgoing_referrer = script_url;
217 job_coordinator()->Register(
218 script_url, options, std::move(outside_fetch_client_settings_object),
219 SaveRegistration(expected_status, ®istration, run_loop.QuitClosure()));
220 run_loop.Run();
221 return registration;
222 }
223
RunUnregisterJob(const GURL & scope,blink::ServiceWorkerStatusCode expected_status)224 void ServiceWorkerJobTest::RunUnregisterJob(
225 const GURL& scope,
226 blink::ServiceWorkerStatusCode expected_status) {
227 base::RunLoop run_loop;
228 job_coordinator()->Unregister(
229 scope, /*is_immediate=*/false,
230 SaveUnregistration(expected_status, run_loop.QuitClosure()));
231 run_loop.Run();
232 }
233
WaitForVersionRunningStatus(scoped_refptr<ServiceWorkerVersion> version,EmbeddedWorkerStatus running_status)234 void ServiceWorkerJobTest::WaitForVersionRunningStatus(
235 scoped_refptr<ServiceWorkerVersion> version,
236 EmbeddedWorkerStatus running_status) {
237 if (version->running_status() == running_status)
238 return;
239
240 base::RunLoop run_loop;
241 EmbeddedWorkerStatusObserver observer(run_loop.QuitClosure(), running_status);
242 version->AddObserver(&observer);
243 run_loop.Run();
244 version->RemoveObserver(&observer);
245 }
246
247 scoped_refptr<ServiceWorkerRegistration>
FindRegistrationForScope(const GURL & scope,blink::ServiceWorkerStatusCode expected_status)248 ServiceWorkerJobTest::FindRegistrationForScope(
249 const GURL& scope,
250 blink::ServiceWorkerStatusCode expected_status) {
251 scoped_refptr<ServiceWorkerRegistration> registration;
252 base::RunLoop run_loop;
253 registry()->FindRegistrationForScope(
254 scope, SaveFoundRegistration(expected_status, ®istration,
255 run_loop.QuitClosure()));
256 run_loop.Run();
257 return registration;
258 }
259
CreateControllee()260 ServiceWorkerContainerHost* ServiceWorkerJobTest::CreateControllee() {
261 remote_endpoints_.emplace_back();
262 base::WeakPtr<ServiceWorkerContainerHost> container_host =
263 CreateContainerHostForWindow(
264 33 /* dummy render process id */, true /* is_parent_frame_secure */,
265 helper_->context()->AsWeakPtr(), &remote_endpoints_.back());
266 return container_host.get();
267 }
268
269 scoped_refptr<ServiceWorkerRegistration>
CreateRegistrationWithControllee(const GURL & script_url,const GURL & scope_url)270 ServiceWorkerJobTest::CreateRegistrationWithControllee(const GURL& script_url,
271 const GURL& scope_url) {
272 blink::mojom::ServiceWorkerRegistrationOptions options;
273 options.scope = scope_url;
274
275 scoped_refptr<ServiceWorkerRegistration> registration =
276 RunRegisterJob(script_url, options);
277
278 auto runner = base::MakeRefCounted<base::TestSimpleTaskRunner>();
279 registration->SetTaskRunnerForTest(runner);
280
281 TestServiceWorkerObserver observer(helper_->context_wrapper());
282 observer.RunUntilActivated(registration->installing_version(), runner);
283
284 ServiceWorkerContainerHost* container_host = CreateControllee();
285 container_host->UpdateUrls(scope_url, net::SiteForCookies::FromUrl(scope_url),
286 url::Origin::Create(scope_url));
287 container_host->SetControllerRegistration(registration,
288 /*notify_controllerchange=*/false);
289 return registration;
290 }
291
TEST_F(ServiceWorkerJobTest,SameDocumentSameRegistration)292 TEST_F(ServiceWorkerJobTest, SameDocumentSameRegistration) {
293 blink::mojom::ServiceWorkerRegistrationOptions options;
294 options.scope = GURL("https://www.example.com/");
295 scoped_refptr<ServiceWorkerRegistration> original_registration =
296 RunRegisterJob(GURL("https://www.example.com/service_worker.js"),
297 options);
298 scoped_refptr<ServiceWorkerRegistration> registration1;
299 base::RunLoop run_loop;
300 base::RepeatingClosure barrier_closure =
301 base::BarrierClosure(2, run_loop.QuitClosure());
302 registry()->FindRegistrationForClientUrl(
303 GURL("https://www.example.com/"),
304 SaveFoundRegistration(blink::ServiceWorkerStatusCode::kOk, ®istration1,
305 barrier_closure));
306 scoped_refptr<ServiceWorkerRegistration> registration2;
307 registry()->FindRegistrationForClientUrl(
308 GURL("https://www.example.com/"),
309 SaveFoundRegistration(blink::ServiceWorkerStatusCode::kOk, ®istration2,
310 barrier_closure));
311 run_loop.Run();
312 ASSERT_TRUE(registration1.get());
313 ASSERT_EQ(registration1, original_registration);
314 ASSERT_EQ(registration1, registration2);
315 }
316
TEST_F(ServiceWorkerJobTest,SameMatchSameRegistration)317 TEST_F(ServiceWorkerJobTest, SameMatchSameRegistration) {
318 blink::mojom::ServiceWorkerRegistrationOptions options;
319 options.scope = GURL("https://www.example.com/");
320 scoped_refptr<ServiceWorkerRegistration> original_registration =
321 RunRegisterJob(GURL("https://www.example.com/service_worker.js"),
322 options);
323 ASSERT_NE(static_cast<ServiceWorkerRegistration*>(nullptr),
324 original_registration.get());
325
326 scoped_refptr<ServiceWorkerRegistration> registration1;
327 base::RunLoop run_loop;
328 base::RepeatingClosure barrier_closure =
329 base::BarrierClosure(2, run_loop.QuitClosure());
330 registry()->FindRegistrationForClientUrl(
331 GURL("https://www.example.com/one"),
332 SaveFoundRegistration(blink::ServiceWorkerStatusCode::kOk, ®istration1,
333 barrier_closure));
334
335 scoped_refptr<ServiceWorkerRegistration> registration2;
336 registry()->FindRegistrationForClientUrl(
337 GURL("https://www.example.com/two"),
338 SaveFoundRegistration(blink::ServiceWorkerStatusCode::kOk, ®istration2,
339 barrier_closure));
340 run_loop.Run();
341 ASSERT_EQ(registration1, original_registration);
342 ASSERT_EQ(registration1, registration2);
343 }
344
TEST_F(ServiceWorkerJobTest,DifferentMatchDifferentRegistration)345 TEST_F(ServiceWorkerJobTest, DifferentMatchDifferentRegistration) {
346 const GURL scope1("https://www.example.com/one");
347 const GURL scope2("https://www.example.com/two");
348 const GURL script_url("https://www.example.com/service_worker.js");
349 blink::mojom::ServiceWorkerRegistrationOptions options1;
350 options1.scope = scope1;
351 blink::mojom::ServiceWorkerRegistrationOptions options2;
352 options2.scope = scope2;
353
354 RunRegisterJob(script_url, options1);
355 RunRegisterJob(script_url, options2);
356
357 scoped_refptr<ServiceWorkerRegistration> registration1;
358 base::RunLoop run_loop;
359 base::RepeatingClosure barrier_closure =
360 base::BarrierClosure(2, run_loop.QuitClosure());
361 registry()->FindRegistrationForClientUrl(
362 scope1, SaveFoundRegistration(blink::ServiceWorkerStatusCode::kOk,
363 ®istration1, barrier_closure));
364 scoped_refptr<ServiceWorkerRegistration> registration2;
365 registry()->FindRegistrationForClientUrl(
366 scope2, SaveFoundRegistration(blink::ServiceWorkerStatusCode::kOk,
367 ®istration2, barrier_closure));
368
369 run_loop.Run();
370 ASSERT_NE(registration1, registration2);
371 }
372
373 class RecordInstallActivateWorker : public FakeServiceWorker {
374 public:
RecordInstallActivateWorker(EmbeddedWorkerTestHelper * helper)375 RecordInstallActivateWorker(EmbeddedWorkerTestHelper* helper)
376 : FakeServiceWorker(helper) {}
377 ~RecordInstallActivateWorker() override = default;
378
events() const379 const std::vector<ServiceWorkerMetrics::EventType>& events() const {
380 return events_;
381 }
382
DispatchInstallEvent(blink::mojom::ServiceWorker::DispatchInstallEventCallback callback)383 void DispatchInstallEvent(
384 blink::mojom::ServiceWorker::DispatchInstallEventCallback callback)
385 override {
386 events_.emplace_back(ServiceWorkerMetrics::EventType::INSTALL);
387 FakeServiceWorker::DispatchInstallEvent(std::move(callback));
388 }
389
DispatchActivateEvent(blink::mojom::ServiceWorker::DispatchActivateEventCallback callback)390 void DispatchActivateEvent(
391 blink::mojom::ServiceWorker::DispatchActivateEventCallback callback)
392 override {
393 events_.emplace_back(ServiceWorkerMetrics::EventType::ACTIVATE);
394 FakeServiceWorker::DispatchActivateEvent(std::move(callback));
395 }
396
397 private:
398 std::vector<ServiceWorkerMetrics::EventType> events_;
399 };
400
401 // Make sure basic registration is working.
TEST_F(ServiceWorkerJobTest,Register)402 TEST_F(ServiceWorkerJobTest, Register) {
403 blink::mojom::ServiceWorkerRegistrationOptions options;
404 options.scope = GURL("https://www.example.com/");
405 auto* worker =
406 helper_->AddNewPendingServiceWorker<RecordInstallActivateWorker>(
407 helper_.get());
408 scoped_refptr<ServiceWorkerRegistration> registration = RunRegisterJob(
409 GURL("https://www.example.com/service_worker.js"), options);
410 auto runner = base::MakeRefCounted<base::TestSimpleTaskRunner>();
411 registration->SetTaskRunnerForTest(runner);
412 TestServiceWorkerObserver observer(helper_->context_wrapper());
413 observer.RunUntilActivated(registration->installing_version(), runner);
414 scoped_refptr<ServiceWorkerVersion> version = registration->active_version();
415
416 EXPECT_TRUE(registration);
417 ASSERT_EQ(2u, worker->events().size());
418 EXPECT_EQ(ServiceWorkerMetrics::EventType::INSTALL, worker->events()[0]);
419 EXPECT_EQ(ServiceWorkerMetrics::EventType::ACTIVATE, worker->events()[1]);
420 }
421
422 // Make sure registrations are cleaned up when they are unregistered.
TEST_F(ServiceWorkerJobTest,Unregister)423 TEST_F(ServiceWorkerJobTest, Unregister) {
424 blink::mojom::ServiceWorkerRegistrationOptions options;
425 options.scope = GURL("https://www.example.com/");
426 scoped_refptr<ServiceWorkerRegistration> registration = RunRegisterJob(
427 GURL("https://www.example.com/service_worker.js"), options);
428 auto runner = base::MakeRefCounted<base::TestSimpleTaskRunner>();
429 registration->SetTaskRunnerForTest(runner);
430 TestServiceWorkerObserver observer(helper_->context_wrapper());
431 observer.RunUntilActivated(registration->installing_version(), runner);
432 scoped_refptr<ServiceWorkerVersion> version = registration->active_version();
433
434 ServiceWorkerHost* worker_host =
435 registration->active_version()->worker_host();
436 ASSERT_NE(nullptr, worker_host);
437 ServiceWorkerContainerHost* container_host = worker_host->container_host();
438 // One ServiceWorkerRegistrationObjectHost should have been created for the
439 // new registration.
440 EXPECT_EQ(1UL, container_host->registration_object_hosts_.size());
441 // One ServiceWorkerObjectHost should have been created for the new service
442 // worker.
443 EXPECT_EQ(1UL, container_host->service_worker_object_hosts_.size());
444
445 RunUnregisterJob(options.scope);
446
447 WaitForVersionRunningStatus(version, EmbeddedWorkerStatus::STOPPED);
448 registry()->GetRemoteStorageControl().FlushForTesting();
449
450 // The service worker registration object host and service worker object host
451 // have been destroyed together with |worker_host| by the above
452 // unregistration. Then |registration| and |version| should be the last one
453 // reference to the corresponding instance.
454 EXPECT_TRUE(registration->HasOneRef());
455 EXPECT_TRUE(version->HasOneRef());
456 EXPECT_EQ(EmbeddedWorkerStatus::STOPPED, version->running_status());
457 EXPECT_EQ(ServiceWorkerVersion::REDUNDANT, version->status());
458
459 registration = FindRegistrationForScope(
460 options.scope, blink::ServiceWorkerStatusCode::kErrorNotFound);
461
462 EXPECT_FALSE(registration);
463 }
464
TEST_F(ServiceWorkerJobTest,Unregister_NothingRegistered)465 TEST_F(ServiceWorkerJobTest, Unregister_NothingRegistered) {
466 GURL scope("https://www.example.com/");
467
468 RunUnregisterJob(scope, blink::ServiceWorkerStatusCode::kErrorNotFound);
469 }
470
TEST_F(ServiceWorkerJobTest,UnregisterImmediate)471 TEST_F(ServiceWorkerJobTest, UnregisterImmediate) {
472 const GURL scope("https://www.example.com/one/");
473
474 scoped_refptr<ServiceWorkerRegistration> registration =
475 CreateRegistrationWithControllee(
476 GURL("https://www.example.com/service_worker.js"), scope);
477
478 EXPECT_NE(nullptr, registration->active_version());
479
480 base::RunLoop run_loop;
481 job_coordinator()->Unregister(
482 scope, /*is_immediate=*/true,
483 SaveUnregistration(blink::ServiceWorkerStatusCode::kOk,
484 run_loop.QuitClosure()));
485
486 run_loop.Run();
487
488 EXPECT_TRUE(registration->is_uninstalled());
489 EXPECT_EQ(nullptr, registration->active_version());
490 EXPECT_EQ(nullptr, registration->waiting_version());
491 EXPECT_EQ(nullptr, registration->installing_version());
492 }
493
494 // Make sure registering a new script creates a new version and shares an
495 // existing registration.
TEST_F(ServiceWorkerJobTest,RegisterNewScript)496 TEST_F(ServiceWorkerJobTest, RegisterNewScript) {
497 blink::mojom::ServiceWorkerRegistrationOptions options;
498 options.scope = GURL("https://www.example.com/");
499 scoped_refptr<ServiceWorkerRegistration> old_registration = RunRegisterJob(
500 GURL("https://www.example.com/service_worker.js"), options);
501 auto runner = base::MakeRefCounted<base::TestSimpleTaskRunner>();
502 old_registration->SetTaskRunnerForTest(runner);
503 TestServiceWorkerObserver observer(helper_->context_wrapper());
504 observer.RunUntilActivated(old_registration->installing_version(), runner);
505
506 scoped_refptr<ServiceWorkerRegistration> old_registration_by_scope =
507 FindRegistrationForScope(options.scope);
508
509 ASSERT_EQ(old_registration, old_registration_by_scope);
510 old_registration_by_scope = nullptr;
511
512 scoped_refptr<ServiceWorkerRegistration> new_registration = RunRegisterJob(
513 GURL("https://www.example.com/service_worker_new.js"), options);
514
515 ASSERT_EQ(old_registration, new_registration);
516
517 scoped_refptr<ServiceWorkerRegistration> new_registration_by_scope =
518 FindRegistrationForScope(options.scope);
519
520 ASSERT_EQ(new_registration, new_registration_by_scope);
521 }
522
523 // Make sure that when registering a duplicate scope+script_url
524 // combination, that the same registration is used.
TEST_F(ServiceWorkerJobTest,RegisterDuplicateScript)525 TEST_F(ServiceWorkerJobTest, RegisterDuplicateScript) {
526 GURL script_url("https://www.example.com/service_worker.js");
527 blink::mojom::ServiceWorkerRegistrationOptions options;
528 options.scope = GURL("https://www.example.com/");
529
530 scoped_refptr<ServiceWorkerRegistration> old_registration =
531 RunRegisterJob(script_url, options);
532 // Wait until the worker becomes active.
533 base::RunLoop().RunUntilIdle();
534
535 // During the above registration, a service worker registration object host
536 // for ServiceWorkerGlobalScope#registration has been created/added into
537 // |worker_host|.
538 ServiceWorkerHost* worker_host =
539 old_registration->active_version()->worker_host();
540 ASSERT_NE(nullptr, worker_host);
541 ServiceWorkerContainerHost* container_host = worker_host->container_host();
542
543 // Clear all service worker object hosts.
544 container_host->service_worker_object_hosts_.clear();
545 // Ensure that the registration's object host doesn't have the reference.
546 EXPECT_EQ(1UL, container_host->registration_object_hosts_.size());
547 container_host->registration_object_hosts_.clear();
548 EXPECT_EQ(0UL, container_host->registration_object_hosts_.size());
549 ASSERT_TRUE(old_registration->HasOneRef());
550
551 scoped_refptr<ServiceWorkerRegistration> old_registration_by_scope =
552 FindRegistrationForScope(options.scope);
553
554 ASSERT_TRUE(old_registration_by_scope.get());
555
556 scoped_refptr<ServiceWorkerRegistration> new_registration =
557 RunRegisterJob(script_url, options);
558
559 ASSERT_EQ(old_registration, new_registration);
560
561 ASSERT_FALSE(old_registration->HasOneRef());
562
563 scoped_refptr<ServiceWorkerRegistration> new_registration_by_scope =
564 FindRegistrationForScope(options.scope);
565
566 EXPECT_EQ(new_registration_by_scope, old_registration);
567 }
568
569 // An instance client that breaks the Mojo connection upon receiving the
570 // Start() message.
571 class FailStartInstanceClient : public FakeEmbeddedWorkerInstanceClient {
572 public:
FailStartInstanceClient(EmbeddedWorkerTestHelper * helper)573 FailStartInstanceClient(EmbeddedWorkerTestHelper* helper)
574 : FakeEmbeddedWorkerInstanceClient(helper) {}
575
StartWorker(blink::mojom::EmbeddedWorkerStartParamsPtr params)576 void StartWorker(blink::mojom::EmbeddedWorkerStartParamsPtr params) override {
577 // Don't save the Mojo ptrs. The connection breaks.
578 }
579 };
580
TEST_F(ServiceWorkerJobTest,Register_FailToStartWorker)581 TEST_F(ServiceWorkerJobTest, Register_FailToStartWorker) {
582 helper_->AddPendingInstanceClient(
583 std::make_unique<FailStartInstanceClient>(helper_.get()));
584
585 blink::mojom::ServiceWorkerRegistrationOptions options;
586 options.scope = GURL("https://www.example.com/");
587 scoped_refptr<ServiceWorkerRegistration> registration =
588 RunRegisterJob(GURL("https://www.example.com/service_worker.js"), options,
589 blink::ServiceWorkerStatusCode::kErrorStartWorkerFailed);
590
591 ASSERT_EQ(scoped_refptr<ServiceWorkerRegistration>(nullptr), registration);
592 }
593
594 // Register and then unregister the scope, in parallel. Job coordinator should
595 // process jobs until the last job.
TEST_F(ServiceWorkerJobTest,ParallelRegUnreg)596 TEST_F(ServiceWorkerJobTest, ParallelRegUnreg) {
597 GURL script_url("https://www.example.com/service_worker.js");
598 blink::mojom::ServiceWorkerRegistrationOptions options;
599 options.scope = GURL("https://www.example.com/");
600 scoped_refptr<ServiceWorkerRegistration> registration =
601 RunRegisterJob(script_url, options);
602
603 RunUnregisterJob(options.scope);
604
605 registration = FindRegistrationForScope(
606 options.scope, blink::ServiceWorkerStatusCode::kErrorNotFound);
607
608 ASSERT_EQ(scoped_refptr<ServiceWorkerRegistration>(), registration);
609 }
610
611 // Register conflicting scripts for the same scope. The most recent
612 // registration should win, and the old registration should have been
613 // shutdown.
TEST_F(ServiceWorkerJobTest,ParallelRegNewScript)614 TEST_F(ServiceWorkerJobTest, ParallelRegNewScript) {
615 GURL scope("https://www.example.com/");
616
617 GURL script_url1("https://www.example.com/service_worker1.js");
618 scoped_refptr<ServiceWorkerRegistration> registration1 = RunRegisterJob(
619 script_url1, blink::mojom::ServiceWorkerRegistrationOptions(
620 scope, blink::mojom::ScriptType::kClassic,
621 blink::mojom::ServiceWorkerUpdateViaCache::kNone));
622
623 GURL script_url2("https://www.example.com/service_worker2.js");
624 scoped_refptr<ServiceWorkerRegistration> registration2 = RunRegisterJob(
625 script_url2, blink::mojom::ServiceWorkerRegistrationOptions(
626 scope, blink::mojom::ScriptType::kClassic,
627 blink::mojom::ServiceWorkerUpdateViaCache::kAll));
628
629 scoped_refptr<ServiceWorkerRegistration> registration =
630 FindRegistrationForScope(scope);
631
632 ASSERT_EQ(registration2, registration);
633 }
634
635 // Register the exact same scope + script. Requests should be
636 // coalesced such that both callers get the exact same registration
637 // object.
TEST_F(ServiceWorkerJobTest,ParallelRegSameScript)638 TEST_F(ServiceWorkerJobTest, ParallelRegSameScript) {
639 blink::mojom::ServiceWorkerRegistrationOptions options;
640 options.scope = GURL("https://www.example.com/");
641
642 GURL script_url("https://www.example.com/service_worker1.js");
643 scoped_refptr<ServiceWorkerRegistration> registration1 =
644 RunRegisterJob(script_url, options);
645
646 scoped_refptr<ServiceWorkerRegistration> registration2 =
647 RunRegisterJob(script_url, options);
648
649 ASSERT_EQ(registration1, registration2);
650
651 scoped_refptr<ServiceWorkerRegistration> registration =
652 FindRegistrationForScope(options.scope);
653
654 ASSERT_EQ(registration, registration1);
655 }
656
657 // Call simulataneous unregister calls.
TEST_F(ServiceWorkerJobTest,ParallelUnreg)658 TEST_F(ServiceWorkerJobTest, ParallelUnreg) {
659 GURL scope("https://www.example.com/");
660
661 GURL script_url("https://www.example.com/service_worker.js");
662 RunUnregisterJob(scope, blink::ServiceWorkerStatusCode::kErrorNotFound);
663
664 RunUnregisterJob(scope, blink::ServiceWorkerStatusCode::kErrorNotFound);
665
666 // There isn't really a way to test that they are being coalesced,
667 // but we can make sure they can exist simultaneously without
668 // crashing.
669 scoped_refptr<ServiceWorkerRegistration> registration =
670 FindRegistrationForScope(scope,
671 blink::ServiceWorkerStatusCode::kErrorNotFound);
672
673 ASSERT_EQ(scoped_refptr<ServiceWorkerRegistration>(), registration);
674 }
675
TEST_F(ServiceWorkerJobTest,AbortAll_Register)676 TEST_F(ServiceWorkerJobTest, AbortAll_Register) {
677 GURL script_url1("https://www1.example.com/service_worker.js");
678 GURL script_url2("https://www2.example.com/service_worker.js");
679
680 blink::mojom::ServiceWorkerRegistrationOptions options1;
681 options1.scope = GURL("https://www1.example.com/");
682 blink::mojom::ServiceWorkerRegistrationOptions options2;
683 options2.scope = GURL("https://www2.example.com/");
684
685 scoped_refptr<ServiceWorkerRegistration> registration1;
686 base::RunLoop run_loop;
687 base::RepeatingClosure barrier_closure =
688 base::BarrierClosure(2, run_loop.QuitClosure());
689 job_coordinator()->Register(
690 script_url1, options1, blink::mojom::FetchClientSettingsObject::New(),
691 SaveRegistration(blink::ServiceWorkerStatusCode::kErrorAbort,
692 ®istration1, barrier_closure));
693
694 scoped_refptr<ServiceWorkerRegistration> registration2;
695 job_coordinator()->Register(
696 script_url2, options2, blink::mojom::FetchClientSettingsObject::New(),
697 SaveRegistration(blink::ServiceWorkerStatusCode::kErrorAbort,
698 ®istration2, barrier_closure));
699
700 job_coordinator()->AbortAll();
701
702 run_loop.Run();
703
704 registration1 = FindRegistrationForScope(
705 options1.scope, blink::ServiceWorkerStatusCode::kErrorNotFound);
706
707 registration2 = FindRegistrationForScope(
708 options2.scope, blink::ServiceWorkerStatusCode::kErrorNotFound);
709
710 EXPECT_EQ(scoped_refptr<ServiceWorkerRegistration>(), registration1);
711 EXPECT_EQ(scoped_refptr<ServiceWorkerRegistration>(), registration2);
712 }
713
TEST_F(ServiceWorkerJobTest,AbortAll_Unregister)714 TEST_F(ServiceWorkerJobTest, AbortAll_Unregister) {
715 GURL scope1("https://www1.example.com/");
716 GURL scope2("https://www2.example.com/");
717
718 scoped_refptr<ServiceWorkerRegistration> registration1;
719 base::RunLoop run_loop;
720 base::RepeatingClosure barrier_closure =
721 base::BarrierClosure(2, run_loop.QuitClosure());
722 job_coordinator()->Unregister(
723 scope1, /*is_immediate=*/false,
724 SaveUnregistration(blink::ServiceWorkerStatusCode::kErrorAbort,
725 barrier_closure));
726
727 job_coordinator()->Unregister(
728 scope2, /*is_immediate=*/false,
729 SaveUnregistration(blink::ServiceWorkerStatusCode::kErrorAbort,
730 barrier_closure));
731
732 job_coordinator()->AbortAll();
733
734 run_loop.Run();
735 }
736
TEST_F(ServiceWorkerJobTest,AbortAll_RegUnreg)737 TEST_F(ServiceWorkerJobTest, AbortAll_RegUnreg) {
738 GURL script_url("https://www.example.com/service_worker.js");
739 blink::mojom::ServiceWorkerRegistrationOptions options;
740 options.scope = GURL("https://www.example.com/");
741
742 scoped_refptr<ServiceWorkerRegistration> registration;
743 base::RunLoop run_loop;
744 base::RepeatingClosure barrier_closure =
745 base::BarrierClosure(2, run_loop.QuitClosure());
746 job_coordinator()->Register(
747 script_url, options, blink::mojom::FetchClientSettingsObject::New(),
748 SaveRegistration(blink::ServiceWorkerStatusCode::kErrorAbort,
749 ®istration, barrier_closure));
750
751 job_coordinator()->Unregister(
752 options.scope, /*is_immediate=*/false,
753 SaveUnregistration(blink::ServiceWorkerStatusCode::kErrorAbort,
754 barrier_closure));
755
756 job_coordinator()->AbortAll();
757
758 run_loop.Run();
759
760 registration = FindRegistrationForScope(
761 options.scope, blink::ServiceWorkerStatusCode::kErrorNotFound);
762
763 EXPECT_EQ(scoped_refptr<ServiceWorkerRegistration>(), registration);
764 }
765
TEST_F(ServiceWorkerJobTest,AbortScope)766 TEST_F(ServiceWorkerJobTest, AbortScope) {
767 GURL script_url("https://www.example.com/service_worker.js");
768 blink::mojom::ServiceWorkerRegistrationOptions options1;
769 options1.scope = GURL("https://www.example.com/1");
770 blink::mojom::ServiceWorkerRegistrationOptions options2;
771 options2.scope = GURL("https://www.example.com/2");
772
773 scoped_refptr<ServiceWorkerRegistration> registration1;
774 base::RunLoop run_loop;
775 base::RepeatingClosure barrier_closure =
776 base::BarrierClosure(2, run_loop.QuitClosure());
777 job_coordinator()->Register(
778 script_url, options1, blink::mojom::FetchClientSettingsObject::New(),
779 SaveRegistration(blink::ServiceWorkerStatusCode::kErrorAbort,
780 ®istration1, barrier_closure));
781
782 scoped_refptr<ServiceWorkerRegistration> registration2;
783 job_coordinator()->Register(
784 script_url, options2, blink::mojom::FetchClientSettingsObject::New(),
785 SaveRegistration(blink::ServiceWorkerStatusCode::kOk, ®istration2,
786 barrier_closure));
787
788 job_coordinator()->Abort(options1.scope);
789
790 run_loop.Run();
791
792 registration1 = FindRegistrationForScope(
793 options1.scope, blink::ServiceWorkerStatusCode::kErrorNotFound);
794 EXPECT_EQ(nullptr, registration1);
795
796 registration2 = FindRegistrationForScope(options2.scope,
797 blink::ServiceWorkerStatusCode::kOk);
798 EXPECT_NE(nullptr, registration2);
799 }
800
801 // Tests that the waiting worker enters the 'redundant' state upon
802 // unregistration.
TEST_F(ServiceWorkerJobTest,UnregisterWaitingSetsRedundant)803 TEST_F(ServiceWorkerJobTest, UnregisterWaitingSetsRedundant) {
804 GURL script_url("https://www.example.com/service_worker.js");
805 blink::mojom::ServiceWorkerRegistrationOptions options;
806 options.scope = GURL("https://www.example.com/");
807 scoped_refptr<ServiceWorkerRegistration> registration =
808 RunRegisterJob(script_url, options);
809 ASSERT_TRUE(registration.get());
810
811 // Manually create the waiting worker since there is no way to become a
812 // waiting worker until Update is implemented.
813 scoped_refptr<ServiceWorkerVersion> version = new ServiceWorkerVersion(
814 registration.get(), script_url, blink::mojom::ScriptType::kClassic, 1L,
815 mojo::PendingRemote<storage::mojom::ServiceWorkerLiveVersionRef>(),
816 helper_->context()->AsWeakPtr());
817 ASSERT_EQ(blink::ServiceWorkerStatusCode::kOk,
818 StartServiceWorker(version.get()));
819
820 EXPECT_EQ(version->fetch_handler_existence(),
821 ServiceWorkerVersion::FetchHandlerExistence::EXISTS);
822 version->SetStatus(ServiceWorkerVersion::INSTALLED);
823 registration->SetWaitingVersion(version);
824 EXPECT_EQ(EmbeddedWorkerStatus::RUNNING, version->running_status());
825 EXPECT_EQ(ServiceWorkerVersion::INSTALLED, version->status());
826
827 RunUnregisterJob(GURL("https://www.example.com/"));
828 WaitForVersionRunningStatus(version, EmbeddedWorkerStatus::STOPPED);
829
830 // The version should be stopped since there is no controllee after
831 // unregistration.
832 EXPECT_EQ(EmbeddedWorkerStatus::STOPPED, version->running_status());
833 EXPECT_EQ(ServiceWorkerVersion::REDUNDANT, version->status());
834 }
835
836 // Tests that the active worker enters the 'redundant' state upon
837 // unregistration.
TEST_F(ServiceWorkerJobTest,UnregisterActiveSetsRedundant)838 TEST_F(ServiceWorkerJobTest, UnregisterActiveSetsRedundant) {
839 blink::mojom::ServiceWorkerRegistrationOptions options;
840 options.scope = GURL("https://www.example.com/");
841 scoped_refptr<ServiceWorkerRegistration> registration = RunRegisterJob(
842 GURL("https://www.example.com/service_worker.js"), options);
843 auto runner = base::MakeRefCounted<base::TestSimpleTaskRunner>();
844 registration->SetTaskRunnerForTest(runner);
845 TestServiceWorkerObserver observer(helper_->context_wrapper());
846 observer.RunUntilActivated(registration->installing_version(), runner);
847 ASSERT_TRUE(registration.get());
848
849 scoped_refptr<ServiceWorkerVersion> version = registration->active_version();
850 observer.RunUntilStatusChange(version.get(), ServiceWorkerVersion::ACTIVATED);
851 EXPECT_EQ(EmbeddedWorkerStatus::RUNNING, version->running_status());
852 EXPECT_EQ(ServiceWorkerVersion::ACTIVATED, version->status());
853
854 RunUnregisterJob(GURL("https://www.example.com/"));
855
856 WaitForVersionRunningStatus(version, EmbeddedWorkerStatus::STOPPED);
857
858 // The version should be stopped since there is no controllee after
859 // unregistration.
860 EXPECT_EQ(EmbeddedWorkerStatus::STOPPED, version->running_status());
861 EXPECT_EQ(ServiceWorkerVersion::REDUNDANT, version->status());
862 }
863
864 // Tests that the active worker enters the 'redundant' state upon
865 // unregistration.
TEST_F(ServiceWorkerJobTest,UnregisterActiveSetsRedundant_WaitForNoControllee)866 TEST_F(ServiceWorkerJobTest,
867 UnregisterActiveSetsRedundant_WaitForNoControllee) {
868 blink::mojom::ServiceWorkerRegistrationOptions options;
869 options.scope = GURL("https://www.example.com/");
870 scoped_refptr<ServiceWorkerRegistration> registration = RunRegisterJob(
871 GURL("https://www.example.com/service_worker.js"), options);
872 auto runner = base::MakeRefCounted<base::TestSimpleTaskRunner>();
873 registration->SetTaskRunnerForTest(runner);
874 TestServiceWorkerObserver observer(helper_->context_wrapper());
875 observer.RunUntilActivated(registration->installing_version(), runner);
876 ASSERT_TRUE(registration.get());
877
878 ServiceWorkerContainerHost* container_host = CreateControllee();
879 registration->active_version()->AddControllee(container_host);
880
881 scoped_refptr<ServiceWorkerVersion> version = registration->active_version();
882 EXPECT_EQ(EmbeddedWorkerStatus::RUNNING, version->running_status());
883 EXPECT_EQ(ServiceWorkerVersion::ACTIVATED, version->status());
884
885 RunUnregisterJob(GURL("https://www.example.com/"));
886
887 // The version should be running since there is still a controllee.
888 EXPECT_EQ(EmbeddedWorkerStatus::RUNNING, version->running_status());
889 EXPECT_EQ(ServiceWorkerVersion::ACTIVATED, version->status());
890
891 registration->active_version()->RemoveControllee(
892 container_host->client_uuid());
893 WaitForVersionRunningStatus(version, EmbeddedWorkerStatus::STOPPED);
894
895 // The version should be stopped since there is no controllee.
896 EXPECT_EQ(EmbeddedWorkerStatus::STOPPED, version->running_status());
897 EXPECT_EQ(ServiceWorkerVersion::REDUNDANT, version->status());
898 }
899
TEST_F(ServiceWorkerJobTest,RegisterWhileUninstalling)900 TEST_F(ServiceWorkerJobTest, RegisterWhileUninstalling) {
901 GURL script1("https://www.example.com/service_worker.js");
902 GURL script2("https://www.example.com/service_worker.js?new");
903 blink::mojom::ServiceWorkerRegistrationOptions options;
904 options.scope = GURL("https://www.example.com/one/");
905
906 auto* initial_client =
907 helper_->AddNewPendingInstanceClient<FakeEmbeddedWorkerInstanceClient>(
908 helper_.get());
909 scoped_refptr<ServiceWorkerRegistration> registration =
910 RunRegisterJob(script1, options);
911 // Wait until the worker becomes active.
912 base::RunLoop().RunUntilIdle();
913 auto runner = base::MakeRefCounted<base::TestSimpleTaskRunner>();
914 registration->SetTaskRunnerForTest(runner);
915
916 // Add a controllee and queue an unregister to force the uninstalling state.
917 ServiceWorkerContainerHost* container_host = CreateControllee();
918 scoped_refptr<ServiceWorkerVersion> old_version =
919 registration->active_version();
920 old_version->AddControllee(container_host);
921 RunUnregisterJob(options.scope);
922
923 // Register another script.
924 EXPECT_EQ(registration, RunRegisterJob(script2, options));
925 // Wait until the worker becomes installed.
926 base::RunLoop().RunUntilIdle();
927
928 EXPECT_FALSE(registration->is_uninstalling());
929 EXPECT_EQ(old_version, registration->active_version());
930 scoped_refptr<ServiceWorkerVersion> new_version =
931 registration->waiting_version();
932
933 // Verify the new version is installed but not activated yet.
934 EXPECT_EQ(nullptr, registration->installing_version());
935 EXPECT_TRUE(new_version);
936 EXPECT_EQ(EmbeddedWorkerStatus::RUNNING, new_version->running_status());
937 EXPECT_EQ(ServiceWorkerVersion::INSTALLED, new_version->status());
938
939 // Make the old version eligible for eviction.
940 old_version->RemoveControllee(container_host->client_uuid());
941 RequestTermination(&initial_client->host());
942
943 // Wait for activated.
944 TestServiceWorkerObserver observer(helper_->context_wrapper());
945 observer.RunUntilActivated(new_version.get(), runner);
946
947 // Verify state after the new version is activated.
948 EXPECT_FALSE(registration->is_uninstalling());
949 EXPECT_FALSE(registration->is_uninstalled());
950 EXPECT_EQ(nullptr, registration->installing_version());
951 EXPECT_EQ(nullptr, registration->waiting_version());
952 EXPECT_EQ(new_version, registration->active_version());
953 EXPECT_EQ(ServiceWorkerVersion::ACTIVATED, new_version->status());
954 }
955
TEST_F(ServiceWorkerJobTest,RegisterAndUnregisterWhileUninstalling)956 TEST_F(ServiceWorkerJobTest, RegisterAndUnregisterWhileUninstalling) {
957 GURL script1("https://www.example.com/service_worker.js");
958 GURL script2("https://www.example.com/service_worker.js?new");
959 blink::mojom::ServiceWorkerRegistrationOptions options;
960 options.scope = GURL("https://www.example.com/one/");
961
962 scoped_refptr<ServiceWorkerRegistration> registration =
963 RunRegisterJob(script1, options);
964 // Wait until the worker becomes active.
965 base::RunLoop().RunUntilIdle();
966
967 // Add a controllee and queue an unregister to force the uninstalling state.
968 ServiceWorkerContainerHost* container_host = CreateControllee();
969 scoped_refptr<ServiceWorkerVersion> old_version =
970 registration->active_version();
971 old_version->AddControllee(container_host);
972 RunUnregisterJob(options.scope);
973
974 EXPECT_EQ(registration, RunRegisterJob(script2, options));
975 // Wait until the worker becomes installed.
976 base::RunLoop().RunUntilIdle();
977
978 EXPECT_EQ(registration, FindRegistrationForScope(options.scope));
979 scoped_refptr<ServiceWorkerVersion> new_version =
980 registration->waiting_version();
981 ASSERT_TRUE(new_version);
982
983 // Unregister the registration (but it's still live).
984 RunUnregisterJob(options.scope);
985 // Now it's not found in the storage.
986 RunUnregisterJob(options.scope,
987 blink::ServiceWorkerStatusCode::kErrorNotFound);
988
989 FindRegistrationForScope(options.scope,
990 blink::ServiceWorkerStatusCode::kErrorNotFound);
991 EXPECT_TRUE(registration->is_uninstalling());
992 EXPECT_EQ(old_version, registration->active_version());
993
994 EXPECT_EQ(EmbeddedWorkerStatus::RUNNING, old_version->running_status());
995 EXPECT_EQ(ServiceWorkerVersion::ACTIVATED, old_version->status());
996 EXPECT_EQ(EmbeddedWorkerStatus::RUNNING, new_version->running_status());
997 EXPECT_EQ(ServiceWorkerVersion::INSTALLED, new_version->status());
998
999 old_version->RemoveControllee(container_host->client_uuid());
1000
1001 WaitForVersionRunningStatus(old_version, EmbeddedWorkerStatus::STOPPED);
1002 WaitForVersionRunningStatus(new_version, EmbeddedWorkerStatus::STOPPED);
1003
1004 EXPECT_FALSE(registration->is_uninstalling());
1005 EXPECT_TRUE(registration->is_uninstalled());
1006
1007 EXPECT_EQ(EmbeddedWorkerStatus::STOPPED, old_version->running_status());
1008 EXPECT_EQ(ServiceWorkerVersion::REDUNDANT, old_version->status());
1009 EXPECT_EQ(EmbeddedWorkerStatus::STOPPED, new_version->running_status());
1010 EXPECT_EQ(ServiceWorkerVersion::REDUNDANT, new_version->status());
1011 }
1012
TEST_F(ServiceWorkerJobTest,RegisterSameScriptMultipleTimesWhileUninstalling)1013 TEST_F(ServiceWorkerJobTest, RegisterSameScriptMultipleTimesWhileUninstalling) {
1014 GURL script1("https://www.example.com/service_worker.js");
1015 GURL script2("https://www.example.com/service_worker.js?new");
1016 blink::mojom::ServiceWorkerRegistrationOptions options;
1017 options.scope = GURL("https://www.example.com/one/");
1018
1019 auto* initial_client =
1020 helper_->AddNewPendingInstanceClient<FakeEmbeddedWorkerInstanceClient>(
1021 helper_.get());
1022 scoped_refptr<ServiceWorkerRegistration> registration =
1023 RunRegisterJob(script1, options);
1024 // Wait until the worker becomes active.
1025 base::RunLoop().RunUntilIdle();
1026 auto runner = base::MakeRefCounted<base::TestSimpleTaskRunner>();
1027 registration->SetTaskRunnerForTest(runner);
1028
1029 // Add a controllee and queue an unregister to force the uninstalling state.
1030 ServiceWorkerContainerHost* container_host = CreateControllee();
1031 scoped_refptr<ServiceWorkerVersion> old_version =
1032 registration->active_version();
1033 old_version->AddControllee(container_host);
1034 RunUnregisterJob(options.scope);
1035
1036 EXPECT_EQ(registration, RunRegisterJob(script2, options));
1037 // Wait until the worker becomes installed.
1038 base::RunLoop().RunUntilIdle();
1039
1040 scoped_refptr<ServiceWorkerVersion> new_version =
1041 registration->waiting_version();
1042 ASSERT_TRUE(new_version);
1043
1044 RunUnregisterJob(options.scope);
1045
1046 EXPECT_TRUE(registration->is_uninstalling());
1047
1048 EXPECT_EQ(registration, RunRegisterJob(script2, options));
1049
1050 EXPECT_FALSE(registration->is_uninstalling());
1051 EXPECT_EQ(new_version, registration->waiting_version());
1052
1053 old_version->RemoveControllee(container_host->client_uuid());
1054 RequestTermination(&initial_client->host());
1055
1056 // Wait for activated.
1057 TestServiceWorkerObserver observer(helper_->context_wrapper());
1058 observer.RunUntilActivated(new_version.get(), runner);
1059
1060 // Verify state after the new version is activated.
1061 EXPECT_FALSE(registration->is_uninstalling());
1062 EXPECT_FALSE(registration->is_uninstalled());
1063 EXPECT_EQ(nullptr, registration->installing_version());
1064 EXPECT_EQ(nullptr, registration->waiting_version());
1065 EXPECT_EQ(new_version, registration->active_version());
1066 EXPECT_EQ(ServiceWorkerVersion::ACTIVATED, new_version->status());
1067 }
1068
1069 // A fake instance client for toggling whether a fetch event handler exists.
1070 class FetchHandlerInstanceClient : public FakeEmbeddedWorkerInstanceClient {
1071 public:
FetchHandlerInstanceClient(EmbeddedWorkerTestHelper * helper)1072 explicit FetchHandlerInstanceClient(EmbeddedWorkerTestHelper* helper)
1073 : FakeEmbeddedWorkerInstanceClient(helper) {}
1074 ~FetchHandlerInstanceClient() override = default;
1075
set_has_fetch_handler(bool has_fetch_handler)1076 void set_has_fetch_handler(bool has_fetch_handler) {
1077 has_fetch_handler_ = has_fetch_handler;
1078 }
1079
1080 protected:
EvaluateScript()1081 void EvaluateScript() override {
1082 host()->OnScriptEvaluationStart();
1083 host()->OnStarted(blink::mojom::ServiceWorkerStartStatus::kNormalCompletion,
1084 has_fetch_handler_, helper()->GetNextThreadId(),
1085 blink::mojom::EmbeddedWorkerStartTiming::New());
1086 }
1087
1088 private:
1089 bool has_fetch_handler_ = false;
1090 };
1091
TEST_F(ServiceWorkerJobTest,HasFetchHandler)1092 TEST_F(ServiceWorkerJobTest, HasFetchHandler) {
1093 GURL script("https://www.example.com/service_worker.js");
1094 blink::mojom::ServiceWorkerRegistrationOptions options;
1095 options.scope = GURL("https://www.example.com/");
1096 scoped_refptr<ServiceWorkerRegistration> registration;
1097
1098 auto* fetch_handler_worker =
1099 helper_->AddNewPendingInstanceClient<FetchHandlerInstanceClient>(
1100 helper_.get());
1101 fetch_handler_worker->set_has_fetch_handler(true);
1102 RunRegisterJob(script, options);
1103 // Wait until the worker becomes active.
1104 base::RunLoop().RunUntilIdle();
1105 registration = FindRegistrationForScope(options.scope);
1106 EXPECT_EQ(ServiceWorkerVersion::FetchHandlerExistence::EXISTS,
1107 registration->active_version()->fetch_handler_existence());
1108 RunUnregisterJob(options.scope);
1109
1110 auto* no_fetch_handler_worker =
1111 helper_->AddNewPendingInstanceClient<FetchHandlerInstanceClient>(
1112 helper_.get());
1113 no_fetch_handler_worker->set_has_fetch_handler(false);
1114 RunRegisterJob(script, options);
1115 // Wait until the worker becomes active.
1116 base::RunLoop().RunUntilIdle();
1117 registration = FindRegistrationForScope(options.scope);
1118 EXPECT_EQ(ServiceWorkerVersion::FetchHandlerExistence::DOES_NOT_EXIST,
1119 registration->active_version()->fetch_handler_existence());
1120 RunUnregisterJob(options.scope);
1121 }
1122
1123 // Test that clients are alerted of new registrations if they are
1124 // in-scope, so that Clients.claim() or ServiceWorkerContainer.ready work
1125 // correctly.
TEST_F(ServiceWorkerJobTest,AddRegistrationToMatchingerHosts)1126 TEST_F(ServiceWorkerJobTest, AddRegistrationToMatchingerHosts) {
1127 GURL scope("https://www.example.com/scope/");
1128 GURL in_scope("https://www.example.com/scope/page");
1129 GURL out_scope("https://www.example.com/page");
1130
1131 // Make an in-scope client.
1132 ServiceWorkerContainerHost* client = CreateControllee();
1133 client->UpdateUrls(in_scope, net::SiteForCookies::FromUrl(in_scope),
1134 url::Origin::Create(in_scope));
1135
1136 // Make an in-scope reserved client.
1137 std::unique_ptr<ServiceWorkerContainerHostAndInfo> host_and_info =
1138 CreateContainerHostAndInfoForWindow(helper_->context()->AsWeakPtr(),
1139 /*are_ancestors_secure=*/true);
1140 base::WeakPtr<ServiceWorkerContainerHost> reserved_client =
1141 host_and_info->host;
1142 reserved_client->UpdateUrls(in_scope, net::SiteForCookies::FromUrl(in_scope),
1143 url::Origin::Create(in_scope));
1144
1145 // Make an out-scope client.
1146 ServiceWorkerContainerHost* out_scope_client = CreateControllee();
1147 out_scope_client->UpdateUrls(out_scope,
1148 net::SiteForCookies::FromUrl(out_scope),
1149 url::Origin::Create(out_scope));
1150
1151 // Make a new registration.
1152 GURL script("https://www.example.com/service_worker.js");
1153 blink::mojom::ServiceWorkerRegistrationOptions options;
1154 options.scope = scope;
1155 scoped_refptr<ServiceWorkerRegistration> registration =
1156 RunRegisterJob(script, options);
1157
1158 EXPECT_EQ(registration.get(), client->MatchRegistration());
1159 EXPECT_EQ(registration.get(), reserved_client->MatchRegistration());
1160 EXPECT_NE(registration.get(), out_scope_client->MatchRegistration());
1161 }
1162
1163 namespace { // Helpers for the update job tests.
1164
1165 const char kNoChangeOrigin[] = "https://nochange/";
1166 const char kScope[] = "scope/";
1167 const char kScript[] = "script.js";
1168
1169 const char kHeaders[] =
1170 "HTTP/1.1 200 OK\n"
1171 "Content-Type: application/javascript\n\n";
1172 const char kBody[] = "/* old body */";
1173 const char kNewBody[] = "/* new body */";
1174
WriteResponse(mojo::Remote<storage::mojom::ServiceWorkerResourceWriter> & writer,const std::string & headers,mojo_base::BigBuffer body)1175 void WriteResponse(
1176 mojo::Remote<storage::mojom::ServiceWorkerResourceWriter>& writer,
1177 const std::string& headers,
1178 mojo_base::BigBuffer body) {
1179 int length = body.size();
1180 auto response_head = network::mojom::URLResponseHead::New();
1181 response_head->request_time = base::Time::Now();
1182 response_head->response_time = base::Time::Now();
1183 response_head->headers = new net::HttpResponseHeaders(headers);
1184 response_head->content_length = length;
1185
1186 int rv = -1234;
1187 {
1188 base::RunLoop loop(base::RunLoop::Type::kNestableTasksAllowed);
1189 writer->WriteResponseHead(std::move(response_head),
1190 base::BindLambdaForTesting([&](int result) {
1191 rv = result;
1192 loop.Quit();
1193 }));
1194 loop.Run();
1195 EXPECT_LT(0, rv);
1196 }
1197
1198 rv = -1234;
1199 {
1200 base::RunLoop loop(base::RunLoop::Type::kNestableTasksAllowed);
1201 writer->WriteData(std::move(body),
1202 base::BindLambdaForTesting([&](int result) {
1203 rv = result;
1204 loop.Quit();
1205 }));
1206 loop.Run();
1207 EXPECT_EQ(length, rv);
1208 }
1209 }
1210
WriteStringResponse(mojo::Remote<storage::mojom::ServiceWorkerResourceWriter> & writer,const std::string & body)1211 void WriteStringResponse(
1212 mojo::Remote<storage::mojom::ServiceWorkerResourceWriter>& writer,
1213 const std::string& body) {
1214 mojo_base::BigBuffer body_buffer(base::as_bytes(base::make_span(body)));
1215 const char kHttpHeaders[] = "HTTP/1.0 200 HONKYDORY\0\0";
1216 std::string headers(kHttpHeaders, base::size(kHttpHeaders));
1217 WriteResponse(writer, headers, std::move(body_buffer));
1218 }
1219
1220 class UpdateJobTestHelper : public EmbeddedWorkerTestHelper,
1221 public ServiceWorkerRegistration::Listener,
1222 public ServiceWorkerContextCoreObserver {
1223 public:
1224 struct AttributeChangeLogEntry {
1225 int64_t registration_id;
1226 blink::mojom::ChangedServiceWorkerObjectsMaskPtr mask;
1227 ServiceWorkerRegistrationInfo info;
1228 };
1229
1230 struct StateChangeLogEntry {
1231 int64_t version_id;
1232 ServiceWorkerVersion::Status status;
1233 };
1234
UpdateJobTestHelper()1235 UpdateJobTestHelper() : EmbeddedWorkerTestHelper(base::FilePath()) {
1236 context_wrapper()->AddObserver(this);
1237 interceptor_ = std::make_unique<URLLoaderInterceptor>(base::BindRepeating(
1238 &FakeNetwork::HandleRequest, base::Unretained(&fake_network_)));
1239 fake_network_.SetDefaultResponse(kHeaders, kBody,
1240 /*network_accessed=*/true, net::OK);
1241 }
~UpdateJobTestHelper()1242 ~UpdateJobTestHelper() override {
1243 context_wrapper()->RemoveObserver(this);
1244 if (observed_registration_.get())
1245 observed_registration_->RemoveListener(this);
1246 }
1247
1248 class ScriptFailureEmbeddedWorkerInstanceClient
1249 : public FakeEmbeddedWorkerInstanceClient {
1250 public:
ScriptFailureEmbeddedWorkerInstanceClient(UpdateJobTestHelper * helper)1251 explicit ScriptFailureEmbeddedWorkerInstanceClient(
1252 UpdateJobTestHelper* helper)
1253 : FakeEmbeddedWorkerInstanceClient(helper) {}
1254 ~ScriptFailureEmbeddedWorkerInstanceClient() override = default;
1255
StartWorker(blink::mojom::EmbeddedWorkerStartParamsPtr params)1256 void StartWorker(
1257 blink::mojom::EmbeddedWorkerStartParamsPtr params) override {
1258 host().Bind(std::move(params->instance_host));
1259 start_params_ = std::move(params);
1260
1261 helper()->OnServiceWorkerReceiver(
1262 std::move(start_params_->service_worker_receiver));
1263 }
1264
SimulateFailureOfScriptEvaluation()1265 void SimulateFailureOfScriptEvaluation() {
1266 host()->OnScriptEvaluationStart();
1267 host()->OnStarted(
1268 blink::mojom::ServiceWorkerStartStatus::kAbruptCompletion,
1269 /*has_fetch_handler=*/false, helper()->GetNextThreadId(),
1270 blink::mojom::EmbeddedWorkerStartTiming::New());
1271 }
1272
1273 private:
1274 blink::mojom::EmbeddedWorkerStartParamsPtr start_params_;
1275 };
1276
1277 class ScriptFailureServiceWorker : public FakeServiceWorker {
1278 public:
ScriptFailureServiceWorker(EmbeddedWorkerTestHelper * helper,ScriptFailureEmbeddedWorkerInstanceClient * client)1279 ScriptFailureServiceWorker(
1280 EmbeddedWorkerTestHelper* helper,
1281 ScriptFailureEmbeddedWorkerInstanceClient* client)
1282 : FakeServiceWorker(helper), client_(client) {}
1283
InitializeGlobalScope(mojo::PendingAssociatedRemote<blink::mojom::ServiceWorkerHost>,blink::mojom::ServiceWorkerRegistrationObjectInfoPtr,blink::mojom::ServiceWorkerObjectInfoPtr,blink::mojom::FetchHandlerExistence,std::unique_ptr<blink::PendingURLLoaderFactoryBundle>,mojo::PendingReceiver<blink::mojom::ReportingObserver>)1284 void InitializeGlobalScope(
1285 mojo::PendingAssociatedRemote<blink::mojom::ServiceWorkerHost>,
1286 blink::mojom::ServiceWorkerRegistrationObjectInfoPtr,
1287 blink::mojom::ServiceWorkerObjectInfoPtr,
1288 blink::mojom::FetchHandlerExistence,
1289 std::unique_ptr<blink::PendingURLLoaderFactoryBundle>,
1290 mojo::PendingReceiver<blink::mojom::ReportingObserver>) override {
1291 client_->SimulateFailureOfScriptEvaluation();
1292 }
1293
1294 private:
1295 ScriptFailureEmbeddedWorkerInstanceClient* client_;
1296 };
1297
job_coordinator()1298 ServiceWorkerJobCoordinator* job_coordinator() {
1299 return context()->job_coordinator();
1300 }
1301
SetupInitialRegistration(const GURL & test_origin)1302 scoped_refptr<ServiceWorkerRegistration> SetupInitialRegistration(
1303 const GURL& test_origin) {
1304 blink::mojom::ServiceWorkerRegistrationOptions options;
1305 options.scope = test_origin.Resolve(kScope);
1306 scoped_refptr<ServiceWorkerRegistration> registration;
1307
1308 auto client = std::make_unique<FakeEmbeddedWorkerInstanceClient>(this);
1309 initial_embedded_worker_instance_client_ = client.get();
1310 AddPendingInstanceClient(std::move(client));
1311 base::RunLoop run_loop;
1312 job_coordinator()->Register(
1313 test_origin.Resolve(kScript), options,
1314 blink::mojom::FetchClientSettingsObject::New(),
1315 SaveRegistration(blink::ServiceWorkerStatusCode::kOk, ®istration,
1316 run_loop.QuitClosure()));
1317 run_loop.Run();
1318 // Wait until the worker becomes active.
1319 base::RunLoop().RunUntilIdle();
1320 EXPECT_TRUE(registration.get());
1321 EXPECT_TRUE(registration->active_version());
1322 EXPECT_FALSE(registration->installing_version());
1323 EXPECT_FALSE(registration->waiting_version());
1324 observed_registration_ = registration;
1325 return registration;
1326 }
1327
1328 // EmbeddedWorkerTestHelper overrides:
PopulateScriptCacheMap(int64_t version_id,base::OnceClosure callback)1329 void PopulateScriptCacheMap(int64_t version_id,
1330 base::OnceClosure callback) override {
1331 context()->GetStorageControl()->GetNewResourceId(base::BindOnce(
1332 &UpdateJobTestHelper::DidGetNewResourceIdForScriptCache,
1333 weak_factory_.GetWeakPtr(), version_id, std::move(callback)));
1334 }
1335
DidGetNewResourceIdForScriptCache(int64_t version_id,base::OnceClosure callback,int64_t resource_id)1336 void DidGetNewResourceIdForScriptCache(int64_t version_id,
1337 base::OnceClosure callback,
1338 int64_t resource_id) {
1339 ServiceWorkerVersion* version = context()->GetLiveVersion(version_id);
1340 ASSERT_TRUE(version);
1341 ServiceWorkerRegistration* registration =
1342 context()->GetLiveRegistration(version->registration_id());
1343 ASSERT_TRUE(registration);
1344 GURL script = version->script_url();
1345 bool is_update = registration->active_version() &&
1346 version != registration->active_version();
1347
1348 mojo::Remote<storage::mojom::ServiceWorkerResourceWriter> writer;
1349 context()->GetStorageControl()->CreateResourceWriter(
1350 resource_id, writer.BindNewPipeAndPassReceiver());
1351 version->script_cache_map()->NotifyStartedCaching(script, resource_id);
1352 if (!is_update) {
1353 // Spoof caching the script for the initial version.
1354 WriteStringResponse(writer, kBody);
1355 version->script_cache_map()->NotifyFinishedCaching(
1356 script, base::size(kBody), net::OK, std::string());
1357 } else {
1358 EXPECT_NE(GURL(kNoChangeOrigin), script.GetOrigin());
1359 // The script must be changed.
1360 WriteStringResponse(writer, kNewBody);
1361 version->script_cache_map()->NotifyFinishedCaching(
1362 script, base::size(kNewBody), net::OK, std::string());
1363 }
1364
1365 version->SetMainScriptResponse(CreateMainScriptResponse());
1366 std::move(callback).Run();
1367 }
1368
1369 // ServiceWorkerContextCoreObserver overrides
OnVersionStateChanged(int64_t version_id,const GURL & scope,ServiceWorkerVersion::Status status)1370 void OnVersionStateChanged(int64_t version_id,
1371 const GURL& scope,
1372 ServiceWorkerVersion::Status status) override {
1373 StateChangeLogEntry entry;
1374 entry.version_id = version_id;
1375 entry.status = status;
1376 state_change_log_.push_back(std::move(entry));
1377 }
1378
1379 // ServiceWorkerRegistration::Listener overrides
OnVersionAttributesChanged(ServiceWorkerRegistration * registration,blink::mojom::ChangedServiceWorkerObjectsMaskPtr changed_mask)1380 void OnVersionAttributesChanged(
1381 ServiceWorkerRegistration* registration,
1382 blink::mojom::ChangedServiceWorkerObjectsMaskPtr changed_mask) override {
1383 AttributeChangeLogEntry entry;
1384 entry.registration_id = registration->id();
1385 entry.mask = std::move(changed_mask);
1386 entry.info = registration->GetInfo();
1387 attribute_change_log_.push_back(std::move(entry));
1388 }
1389
OnRegistrationFailed(ServiceWorkerRegistration * registration)1390 void OnRegistrationFailed(ServiceWorkerRegistration* registration) override {
1391 registration_failed_ = true;
1392 }
1393
OnUpdateFound(ServiceWorkerRegistration * registration)1394 void OnUpdateFound(ServiceWorkerRegistration* registration) override {
1395 update_found_ = true;
1396 }
1397
1398 FakeEmbeddedWorkerInstanceClient* initial_embedded_worker_instance_client_ =
1399 nullptr;
1400 scoped_refptr<ServiceWorkerRegistration> observed_registration_;
1401 std::vector<AttributeChangeLogEntry> attribute_change_log_;
1402 std::vector<StateChangeLogEntry> state_change_log_;
1403 bool update_found_ = false;
1404 bool registration_failed_ = false;
1405 bool force_start_worker_failure_ = false;
1406 base::Optional<bool> will_be_terminated_;
1407
1408 // These are used only when ServiceWorkerImportedScriptUpdateCheck is enabled.
1409 FakeNetwork fake_network_;
1410 std::unique_ptr<URLLoaderInterceptor> interceptor_;
1411
1412 base::WeakPtrFactory<UpdateJobTestHelper> weak_factory_{this};
1413 };
1414
1415 } // namespace
1416
1417 // This class is for cases that can be impacted by different update check
1418 // types.
1419 class ServiceWorkerUpdateJobTest : public ServiceWorkerJobTest {
1420 public:
SetUp()1421 void SetUp() override {
1422 update_helper_ = new UpdateJobTestHelper();
1423 helper_.reset(update_helper_);
1424
1425 // Create a StoragePartition with the testing browser context so that the
1426 // ServiceWorkerUpdateChecker can find the BrowserContext through it.
1427 storage_partition_impl_ = StoragePartitionImpl::Create(
1428 helper_->browser_context(), /* in_memory= */ true, base::FilePath(),
1429 /* partition_domain= */ "");
1430 storage_partition_impl_->Initialize();
1431 helper_->context_wrapper()->set_storage_partition(
1432 storage_partition_impl_.get());
1433 }
1434
1435 protected:
1436 std::unique_ptr<StoragePartitionImpl> storage_partition_impl_;
1437 UpdateJobTestHelper* update_helper_;
1438 };
1439
1440 // Make sure that the same registration is used and the update_via_cache value
1441 // is updated when registering a service worker with the same parameter except
1442 // for updateViaCache.
TEST_F(ServiceWorkerUpdateJobTest,RegisterWithDifferentUpdateViaCache)1443 TEST_F(ServiceWorkerUpdateJobTest, RegisterWithDifferentUpdateViaCache) {
1444 const GURL script_url("https://www.example.com/service_worker.js");
1445 blink::mojom::ServiceWorkerRegistrationOptions options;
1446 options.scope = GURL("https://www.example.com/");
1447
1448 scoped_refptr<ServiceWorkerRegistration> old_registration =
1449 RunRegisterJob(script_url, options);
1450 // Wait until the worker becomes active.
1451 base::RunLoop().RunUntilIdle();
1452
1453 EXPECT_EQ(blink::mojom::ServiceWorkerUpdateViaCache::kImports,
1454 old_registration->update_via_cache());
1455
1456 // During the above registration, a service worker registration object host
1457 // for ServiceWorkerGlobalScope#registration has been created/added into
1458 // |worker_host|.
1459 ServiceWorkerHost* worker_host =
1460 old_registration->active_version()->worker_host();
1461 ASSERT_TRUE(worker_host);
1462 ServiceWorkerContainerHost* container_host = worker_host->container_host();
1463
1464 // Remove references to |old_registration| so that |old_registration| is the
1465 // only reference to the registration.
1466 container_host->service_worker_object_hosts_.clear();
1467 EXPECT_EQ(1UL, container_host->registration_object_hosts_.size());
1468 container_host->registration_object_hosts_.clear();
1469 EXPECT_EQ(0UL, container_host->registration_object_hosts_.size());
1470 EXPECT_TRUE(old_registration->HasOneRef());
1471
1472 EXPECT_TRUE(FindRegistrationForScope(options.scope));
1473
1474 base::HistogramTester histogram_tester;
1475 options.update_via_cache = blink::mojom::ServiceWorkerUpdateViaCache::kNone;
1476 scoped_refptr<ServiceWorkerRegistration> new_registration =
1477 RunRegisterJob(script_url, options);
1478
1479 // Ensure that the registration object is not copied.
1480 EXPECT_EQ(old_registration, new_registration);
1481 EXPECT_EQ(blink::mojom::ServiceWorkerUpdateViaCache::kNone,
1482 new_registration->update_via_cache());
1483
1484 scoped_refptr<ServiceWorkerRegistration> new_registration_by_scope =
1485 FindRegistrationForScope(options.scope);
1486
1487 EXPECT_EQ(new_registration_by_scope, old_registration);
1488 }
1489
TEST_F(ServiceWorkerUpdateJobTest,Update_NoChange)1490 TEST_F(ServiceWorkerUpdateJobTest, Update_NoChange) {
1491 scoped_refptr<ServiceWorkerRegistration> registration =
1492 update_helper_->SetupInitialRegistration(GURL(kNoChangeOrigin));
1493 ASSERT_TRUE(registration.get());
1494 ASSERT_EQ(4u, update_helper_->state_change_log_.size());
1495 EXPECT_EQ(ServiceWorkerVersion::INSTALLING,
1496 update_helper_->state_change_log_[0].status);
1497 EXPECT_EQ(ServiceWorkerVersion::INSTALLED,
1498 update_helper_->state_change_log_[1].status);
1499 EXPECT_EQ(ServiceWorkerVersion::ACTIVATING,
1500 update_helper_->state_change_log_[2].status);
1501 EXPECT_EQ(ServiceWorkerVersion::ACTIVATED,
1502 update_helper_->state_change_log_[3].status);
1503 update_helper_->state_change_log_.clear();
1504
1505 // Run the update job.
1506 base::HistogramTester histogram_tester;
1507 registration->AddListener(update_helper_);
1508 scoped_refptr<ServiceWorkerVersion> first_version =
1509 registration->active_version();
1510 first_version->StartUpdate();
1511 base::RunLoop().RunUntilIdle();
1512
1513 // Verify results.
1514 ASSERT_TRUE(registration->active_version());
1515 EXPECT_EQ(first_version.get(), registration->active_version());
1516 EXPECT_FALSE(registration->installing_version());
1517 EXPECT_FALSE(registration->waiting_version());
1518 EXPECT_TRUE(update_helper_->attribute_change_log_.empty());
1519 EXPECT_FALSE(update_helper_->update_found_);
1520 }
1521
TEST_F(ServiceWorkerUpdateJobTest,Update_BumpLastUpdateCheckTime)1522 TEST_F(ServiceWorkerUpdateJobTest, Update_BumpLastUpdateCheckTime) {
1523 const base::Time kToday = base::Time::Now();
1524 const base::Time kYesterday =
1525 kToday - base::TimeDelta::FromDays(1) - base::TimeDelta::FromHours(1);
1526 const GURL kNewVersionOrigin("https://newversion/");
1527
1528 scoped_refptr<ServiceWorkerRegistration> registration =
1529 update_helper_->SetupInitialRegistration(GURL(kNoChangeOrigin));
1530 ASSERT_TRUE(registration.get());
1531
1532 registration->AddListener(update_helper_);
1533
1534 // Run an update where the script did not change and the network was not
1535 // accessed. The check time should not be updated.
1536 // Set network not accessed.
1537 update_helper_->fake_network_.SetResponse(
1538 GURL(kNoChangeOrigin).Resolve(kScript), kHeaders, kBody,
1539 /*network_accessed=*/false, net::OK);
1540
1541 {
1542 base::HistogramTester histogram_tester;
1543 registration->set_last_update_check(kToday);
1544 registration->active_version()->StartUpdate();
1545 base::RunLoop().RunUntilIdle();
1546 EXPECT_EQ(kToday, registration->last_update_check());
1547 EXPECT_FALSE(update_helper_->update_found_);
1548 }
1549
1550 // Run an update where the script did not change and the network was
1551 // accessed. The check time should be updated.
1552 // Set network accessed.
1553 update_helper_->fake_network_.SetResponse(
1554 GURL(kNoChangeOrigin).Resolve(kScript), kHeaders, kBody,
1555 /*network_accessed=*/true, net::OK);
1556
1557 {
1558 base::HistogramTester histogram_tester;
1559 registration->set_last_update_check(kYesterday);
1560 registration->active_version()->StartUpdate();
1561 base::RunLoop().RunUntilIdle();
1562 EXPECT_LT(kYesterday, registration->last_update_check());
1563 EXPECT_FALSE(update_helper_->update_found_);
1564 registration->RemoveListener(update_helper_);
1565 registration = update_helper_->SetupInitialRegistration(kNewVersionOrigin);
1566 ASSERT_TRUE(registration.get());
1567 }
1568
1569 registration->AddListener(update_helper_);
1570
1571 // Run an update where the script changed. The check time should be updated.
1572 // Change script body.
1573 update_helper_->fake_network_.SetResponse(kNewVersionOrigin.Resolve(kScript),
1574 kHeaders, kNewBody,
1575 /*network_accessed=*/true, net::OK);
1576 {
1577 base::HistogramTester histogram_tester;
1578 registration->set_last_update_check(kYesterday);
1579 registration->active_version()->StartUpdate();
1580 base::RunLoop().RunUntilIdle();
1581 EXPECT_LT(kYesterday, registration->last_update_check());
1582 }
1583
1584 // Run an update to a worker that loads successfully but fails to start up
1585 // (script evaluation failure). The check time should be updated.
1586 auto* embedded_worker_instance_client =
1587 update_helper_->AddNewPendingInstanceClient<
1588 UpdateJobTestHelper::ScriptFailureEmbeddedWorkerInstanceClient>(
1589 update_helper_);
1590 update_helper_->AddNewPendingServiceWorker<
1591 UpdateJobTestHelper::ScriptFailureServiceWorker>(
1592 update_helper_, embedded_worker_instance_client);
1593 registration->set_last_update_check(kYesterday);
1594 // Change script body.
1595 update_helper_->fake_network_.SetResponse(kNewVersionOrigin.Resolve(kScript),
1596 kHeaders, kBody,
1597 /*network_accessed=*/true, net::OK);
1598 {
1599 base::HistogramTester histogram_tester;
1600 registration->active_version()->StartUpdate();
1601 base::RunLoop().RunUntilIdle();
1602 EXPECT_LT(kYesterday, registration->last_update_check());
1603 }
1604 }
1605
TEST_F(ServiceWorkerUpdateJobTest,Update_NewVersion)1606 TEST_F(ServiceWorkerUpdateJobTest, Update_NewVersion) {
1607 const GURL kNewVersionOrigin("https://newversion/");
1608
1609 scoped_refptr<ServiceWorkerRegistration> registration =
1610 update_helper_->SetupInitialRegistration(kNewVersionOrigin);
1611 ASSERT_TRUE(registration.get());
1612 update_helper_->state_change_log_.clear();
1613 auto runner = base::MakeRefCounted<base::TestSimpleTaskRunner>();
1614 registration->SetTaskRunnerForTest(runner);
1615
1616 // Run the update job and an update is found.
1617 // Change script body.
1618 update_helper_->fake_network_.SetResponse(kNewVersionOrigin.Resolve(kScript),
1619 kHeaders, kNewBody,
1620 /*network_accessed=*/true, net::OK);
1621
1622 base::HistogramTester histogram_tester;
1623 registration->AddListener(update_helper_);
1624 scoped_refptr<ServiceWorkerVersion> first_version =
1625 registration->active_version();
1626 first_version->StartUpdate();
1627 base::RunLoop().RunUntilIdle();
1628
1629 // The worker is updated after RequestTermination() is called from the
1630 // renderer. Until then, the active version stays active.
1631 EXPECT_EQ(first_version.get(), registration->active_version());
1632 // The new worker is installed but not yet to be activated.
1633 scoped_refptr<ServiceWorkerVersion> new_version =
1634 registration->waiting_version();
1635 EXPECT_EQ(2u, update_helper_->attribute_change_log_.size());
1636 RequestTermination(
1637 &(update_helper_->initial_embedded_worker_instance_client_->host()));
1638
1639 TestServiceWorkerObserver observer(helper_->context_wrapper());
1640 observer.RunUntilActivated(new_version.get(), runner);
1641
1642 // Pump the loop again. This ensures |update_helper_| observes all
1643 // the status changes, since RunUntilActivated() only ensured
1644 // ServiceWorkerJobTest did.
1645 base::RunLoop().RunUntilIdle();
1646
1647 // Verify results.
1648 ASSERT_TRUE(registration->active_version());
1649 EXPECT_NE(first_version.get(), registration->active_version());
1650 EXPECT_FALSE(registration->installing_version());
1651 EXPECT_FALSE(registration->waiting_version());
1652 ASSERT_EQ(3u, update_helper_->attribute_change_log_.size());
1653
1654 {
1655 const UpdateJobTestHelper::AttributeChangeLogEntry& entry =
1656 update_helper_->attribute_change_log_[0];
1657 EXPECT_TRUE(entry.mask->installing);
1658 EXPECT_FALSE(entry.mask->waiting);
1659 EXPECT_FALSE(entry.mask->active);
1660 EXPECT_NE(entry.info.installing_version.version_id,
1661 blink::mojom::kInvalidServiceWorkerVersionId);
1662 EXPECT_EQ(entry.info.waiting_version.version_id,
1663 blink::mojom::kInvalidServiceWorkerVersionId);
1664 EXPECT_NE(entry.info.active_version.version_id,
1665 blink::mojom::kInvalidServiceWorkerVersionId);
1666 }
1667
1668 {
1669 const UpdateJobTestHelper::AttributeChangeLogEntry& entry =
1670 update_helper_->attribute_change_log_[1];
1671 EXPECT_TRUE(entry.mask->installing);
1672 EXPECT_TRUE(entry.mask->waiting);
1673 EXPECT_FALSE(entry.mask->active);
1674 EXPECT_EQ(entry.info.installing_version.version_id,
1675 blink::mojom::kInvalidServiceWorkerVersionId);
1676 EXPECT_NE(entry.info.waiting_version.version_id,
1677 blink::mojom::kInvalidServiceWorkerVersionId);
1678 EXPECT_NE(entry.info.active_version.version_id,
1679 blink::mojom::kInvalidServiceWorkerVersionId);
1680 }
1681
1682 {
1683 const UpdateJobTestHelper::AttributeChangeLogEntry& entry =
1684 update_helper_->attribute_change_log_[2];
1685 EXPECT_FALSE(entry.mask->installing);
1686 EXPECT_TRUE(entry.mask->waiting);
1687 EXPECT_TRUE(entry.mask->active);
1688 EXPECT_EQ(entry.info.installing_version.version_id,
1689 blink::mojom::kInvalidServiceWorkerVersionId);
1690 EXPECT_EQ(entry.info.waiting_version.version_id,
1691 blink::mojom::kInvalidServiceWorkerVersionId);
1692 EXPECT_NE(entry.info.active_version.version_id,
1693 blink::mojom::kInvalidServiceWorkerVersionId);
1694 }
1695
1696 // expected version state transitions:
1697 // new.installing, new.installed,
1698 // old.redundant,
1699 // new.activating, new.activated
1700 ASSERT_EQ(5u, update_helper_->state_change_log_.size());
1701
1702 EXPECT_EQ(registration->active_version()->version_id(),
1703 update_helper_->state_change_log_[0].version_id);
1704 EXPECT_EQ(ServiceWorkerVersion::INSTALLING,
1705 update_helper_->state_change_log_[0].status);
1706
1707 EXPECT_EQ(registration->active_version()->version_id(),
1708 update_helper_->state_change_log_[1].version_id);
1709 EXPECT_EQ(ServiceWorkerVersion::INSTALLED,
1710 update_helper_->state_change_log_[1].status);
1711
1712 EXPECT_EQ(first_version->version_id(),
1713 update_helper_->state_change_log_[2].version_id);
1714 EXPECT_EQ(ServiceWorkerVersion::REDUNDANT,
1715 update_helper_->state_change_log_[2].status);
1716
1717 EXPECT_EQ(registration->active_version()->version_id(),
1718 update_helper_->state_change_log_[3].version_id);
1719 EXPECT_EQ(ServiceWorkerVersion::ACTIVATING,
1720 update_helper_->state_change_log_[3].status);
1721
1722 EXPECT_EQ(registration->active_version()->version_id(),
1723 update_helper_->state_change_log_[4].version_id);
1724 EXPECT_EQ(ServiceWorkerVersion::ACTIVATED,
1725 update_helper_->state_change_log_[4].status);
1726
1727 EXPECT_TRUE(update_helper_->update_found_);
1728 }
1729
1730 // Test that the update job uses the script URL of the newest worker when the
1731 // job starts, rather than when it is scheduled.
TEST_F(ServiceWorkerUpdateJobTest,Update_ScriptUrlChanged)1732 TEST_F(ServiceWorkerUpdateJobTest, Update_ScriptUrlChanged) {
1733 const GURL old_script("https://www.example.com/service_worker.js");
1734 const GURL new_script("https://www.example.com/new_worker.js");
1735
1736 // Create a registration with an active version.
1737 blink::mojom::ServiceWorkerRegistrationOptions options;
1738 options.scope = GURL("https://www.example.com/one/");
1739 auto* initial_client =
1740 helper_->AddNewPendingInstanceClient<FakeEmbeddedWorkerInstanceClient>(
1741 helper_.get());
1742 // Setup the old script response.
1743 update_helper_->fake_network_.SetResponse(old_script, kHeaders, kBody,
1744 /*network_accessed=*/true, net::OK);
1745 scoped_refptr<ServiceWorkerRegistration> registration =
1746 RunRegisterJob(old_script, options);
1747 // Wait until the worker becomes active.
1748 base::RunLoop().RunUntilIdle();
1749 auto runner = base::MakeRefCounted<base::TestSimpleTaskRunner>();
1750 registration->SetTaskRunnerForTest(runner);
1751
1752 // Queue an Update. When this runs, it will use the waiting version's script.
1753 job_coordinator()->Update(registration.get(), false);
1754
1755 // Add a waiting version with a new script.
1756 scoped_refptr<ServiceWorkerVersion> version = new ServiceWorkerVersion(
1757 registration.get(), new_script, blink::mojom::ScriptType::kClassic,
1758 2L /* dummy version id */,
1759 mojo::PendingRemote<storage::mojom::ServiceWorkerLiveVersionRef>(),
1760 helper_->context()->AsWeakPtr());
1761 registration->SetWaitingVersion(version);
1762
1763 // Setup the new script response.
1764 update_helper_->fake_network_.SetResponse(new_script, kHeaders, kNewBody,
1765 /*network_accessed=*/true, net::OK);
1766
1767 // Make sure the storage has the data of the current waiting version.
1768 const int64_t resource_id = 2;
1769 mojo::Remote<storage::mojom::ServiceWorkerResourceWriter> writer;
1770 context()->GetStorageControl()->CreateResourceWriter(
1771 resource_id, writer.BindNewPipeAndPassReceiver());
1772 version->script_cache_map()->NotifyStartedCaching(new_script, resource_id);
1773 WriteStringResponse(writer, kBody);
1774 version->script_cache_map()->NotifyFinishedCaching(
1775 new_script, base::size(kBody), net::OK, std::string());
1776
1777 // Run the update job.
1778 base::RunLoop().RunUntilIdle();
1779
1780 // The worker is activated after RequestTermination() is called from the
1781 // renderer. Until then, the active version stays active.
1782 // Still waiting, but the waiting version isn't |version| since another
1783 // ServiceWorkerVersion is created during the update job and the job wipes
1784 // out the older waiting version.
1785 ServiceWorkerVersion* waiting_version = registration->waiting_version();
1786 EXPECT_TRUE(registration->active_version());
1787 EXPECT_TRUE(waiting_version);
1788 EXPECT_NE(version.get(), waiting_version);
1789
1790 RequestTermination(&initial_client->host());
1791 TestServiceWorkerObserver observer(helper_->context_wrapper());
1792 observer.RunUntilActivated(waiting_version, runner);
1793
1794 // The update job should have created a new version with the new script,
1795 // and promoted it to the active version.
1796 EXPECT_EQ(new_script, registration->active_version()->script_url());
1797 EXPECT_EQ(nullptr, registration->waiting_version());
1798 EXPECT_EQ(nullptr, registration->installing_version());
1799 }
1800
1801 // Test that update fails if the incumbent worker was evicted
1802 // during the update job (this can happen on disk cache failure).
TEST_F(ServiceWorkerUpdateJobTest,Update_EvictedIncumbent)1803 TEST_F(ServiceWorkerUpdateJobTest, Update_EvictedIncumbent) {
1804 const GURL kNewVersionOrigin("https://newversion/");
1805
1806 scoped_refptr<ServiceWorkerRegistration> registration =
1807 update_helper_->SetupInitialRegistration(kNewVersionOrigin);
1808 ASSERT_TRUE(registration.get());
1809 update_helper_->state_change_log_.clear();
1810
1811 registration->AddListener(update_helper_);
1812 scoped_refptr<ServiceWorkerVersion> first_version =
1813 registration->active_version();
1814 auto* instance_client = helper_->AddNewPendingInstanceClient<
1815 DelayedFakeEmbeddedWorkerInstanceClient>(helper_.get());
1816
1817 // Start the update job and make it block on the worker starting.
1818 // Evict the incumbent during that time.
1819 // Change script body.
1820 update_helper_->fake_network_.SetResponse(kNewVersionOrigin.Resolve(kScript),
1821 kHeaders, kNewBody,
1822 /*network_accessed=*/true, net::OK);
1823
1824 first_version->StartUpdate();
1825 instance_client->RunUntilStartWorker();
1826 registration->ForceDelete();
1827
1828 // Finish the update job.
1829 instance_client->UnblockStartWorker();
1830 base::RunLoop().RunUntilIdle();
1831
1832 // Verify results.
1833 EXPECT_FALSE(registration->GetNewestVersion());
1834 EXPECT_EQ(ServiceWorkerVersion::REDUNDANT, first_version->status());
1835 EXPECT_TRUE(update_helper_->attribute_change_log_.empty());
1836 EXPECT_FALSE(update_helper_->update_found_);
1837 EXPECT_TRUE(update_helper_->registration_failed_);
1838 EXPECT_TRUE(registration->is_uninstalled());
1839 }
1840
TEST_F(ServiceWorkerUpdateJobTest,Update_UninstallingRegistration)1841 TEST_F(ServiceWorkerUpdateJobTest, Update_UninstallingRegistration) {
1842 const GURL scope("https://www.example.com/one/");
1843
1844 // Create a registration with a controllee and queue an unregister to force
1845 // the uninstalling state.
1846 scoped_refptr<ServiceWorkerRegistration> registration =
1847 CreateRegistrationWithControllee(
1848 GURL("https://www.example.com/service_worker.js"), scope);
1849
1850 ServiceWorkerVersion* active_version = registration->active_version();
1851
1852 base::RunLoop run_loop;
1853 job_coordinator()->Unregister(
1854 scope, /*is_immediate=*/false,
1855 SaveUnregistration(blink::ServiceWorkerStatusCode::kOk,
1856 run_loop.QuitClosure()));
1857
1858 // Update should abort after it starts and sees uninstalling.
1859 job_coordinator()->Update(registration.get(), false);
1860
1861 run_loop.Run();
1862
1863 // Verify the registration was not modified by the Update.
1864 EXPECT_TRUE(registration->is_uninstalling());
1865 EXPECT_EQ(active_version, registration->active_version());
1866 EXPECT_EQ(nullptr, registration->waiting_version());
1867 EXPECT_EQ(nullptr, registration->installing_version());
1868 }
1869
TEST_F(ServiceWorkerUpdateJobTest,RegisterMultipleTimesWhileUninstalling)1870 TEST_F(ServiceWorkerUpdateJobTest, RegisterMultipleTimesWhileUninstalling) {
1871 GURL script1("https://www.example.com/service_worker.js?first");
1872 GURL script2("https://www.example.com/service_worker.js?second");
1873 GURL script3("https://www.example.com/service_worker.js?third");
1874 blink::mojom::ServiceWorkerRegistrationOptions options;
1875 options.scope = GURL("https://www.example.com/one/");
1876
1877 auto* initial_client =
1878 helper_->AddNewPendingInstanceClient<FakeEmbeddedWorkerInstanceClient>(
1879 helper_.get());
1880 scoped_refptr<ServiceWorkerRegistration> registration =
1881 RunRegisterJob(script1, options);
1882 // Wait until the worker becomes actvie.
1883 base::RunLoop().RunUntilIdle();
1884 auto runner = base::MakeRefCounted<base::TestSimpleTaskRunner>();
1885 registration->SetTaskRunnerForTest(runner);
1886
1887 // Add a controllee and queue an unregister to force the uninstalling state.
1888 ServiceWorkerContainerHost* container_host = CreateControllee();
1889 scoped_refptr<ServiceWorkerVersion> first_version =
1890 registration->active_version();
1891 first_version->AddControllee(container_host);
1892 RunUnregisterJob(options.scope);
1893
1894 EXPECT_EQ(registration, RunRegisterJob(script2, options));
1895 // Wait until the worker becomes installed.
1896 base::RunLoop().RunUntilIdle();
1897
1898 scoped_refptr<ServiceWorkerVersion> second_version =
1899 registration->waiting_version();
1900 ASSERT_TRUE(second_version);
1901
1902 RunUnregisterJob(options.scope);
1903
1904 EXPECT_TRUE(registration->is_uninstalling());
1905
1906 EXPECT_EQ(registration, RunRegisterJob(script3, options));
1907 TestServiceWorkerObserver observer(helper_->context_wrapper());
1908 observer.RunUntilStatusChange(second_version.get(),
1909 ServiceWorkerVersion::REDUNDANT);
1910 scoped_refptr<ServiceWorkerVersion> third_version =
1911 registration->waiting_version();
1912 ASSERT_TRUE(third_version);
1913
1914 EXPECT_FALSE(registration->is_uninstalling());
1915 EXPECT_EQ(ServiceWorkerVersion::REDUNDANT, second_version->status());
1916
1917 first_version->RemoveControllee(container_host->client_uuid());
1918 RequestTermination(&initial_client->host());
1919
1920 // Wait for activated.
1921 observer.RunUntilActivated(third_version.get(), runner);
1922
1923 // Verify the new version is activated.
1924 EXPECT_FALSE(registration->is_uninstalling());
1925 EXPECT_FALSE(registration->is_uninstalled());
1926 EXPECT_EQ(nullptr, registration->installing_version());
1927 EXPECT_EQ(nullptr, registration->waiting_version());
1928 EXPECT_EQ(third_version, registration->active_version());
1929 EXPECT_EQ(ServiceWorkerVersion::ACTIVATED, third_version->status());
1930 }
1931
1932 // Test that activation doesn't complete if it's triggered by removing a
1933 // controllee and starting the worker failed due to shutdown.
TEST_F(ServiceWorkerUpdateJobTest,ActivateCancelsOnShutdown)1934 TEST_F(ServiceWorkerUpdateJobTest, ActivateCancelsOnShutdown) {
1935 GURL script("https://www.example.com/service_worker.js");
1936 blink::mojom::ServiceWorkerRegistrationOptions options;
1937 options.scope = GURL("https://www.example.com/");
1938
1939 auto* initial_client =
1940 helper_->AddNewPendingInstanceClient<FakeEmbeddedWorkerInstanceClient>(
1941 helper_.get());
1942 scoped_refptr<ServiceWorkerRegistration> registration =
1943 RunRegisterJob(script, options);
1944 // Wait until the worker becomes active.
1945 base::RunLoop().RunUntilIdle();
1946 auto runner = base::MakeRefCounted<base::TestSimpleTaskRunner>();
1947 registration->SetTaskRunnerForTest(runner);
1948
1949 // Add a controllee.
1950 ServiceWorkerContainerHost* container_host = CreateControllee();
1951 scoped_refptr<ServiceWorkerVersion> first_version =
1952 registration->active_version();
1953 first_version->AddControllee(container_host);
1954
1955 // Update. The new version should be waiting.
1956 // Change script body.
1957 update_helper_->fake_network_.SetResponse(script, kHeaders, kNewBody,
1958 /*network_accessed=*/true, net::OK);
1959
1960 registration->AddListener(update_helper_);
1961 first_version->StartUpdate();
1962 base::RunLoop().RunUntilIdle();
1963 scoped_refptr<ServiceWorkerVersion> new_version =
1964 registration->waiting_version();
1965 ASSERT_TRUE(new_version);
1966 EXPECT_EQ(ServiceWorkerVersion::INSTALLED, new_version->status());
1967
1968 // Stop the worker so that it must start again when activation is attempted.
1969 // (This is not strictly necessary to exercise the codepath, but it makes it
1970 // easy to cause a failure with set_force_start_worker_failure after
1971 // shutdown is simulated. Otherwise our test helper often fails on
1972 // DCHECK(context)).
1973 new_version->StopWorker(base::DoNothing());
1974
1975 // Remove the controllee. The new version should be activating, and delayed
1976 // until the runner runs again.
1977 first_version->RemoveControllee(container_host->client_uuid());
1978 base::RunLoop().RunUntilIdle();
1979
1980 // Activating the new version won't happen until
1981 // RequestTermination() is called.
1982 EXPECT_EQ(first_version.get(), registration->active_version());
1983 RequestTermination(&initial_client->host());
1984
1985 TestServiceWorkerObserver observer(helper_->context_wrapper());
1986 observer.RunUntilStatusChange(new_version.get(),
1987 ServiceWorkerVersion::ACTIVATING);
1988 EXPECT_EQ(new_version.get(), registration->active_version());
1989 EXPECT_EQ(ServiceWorkerVersion::ACTIVATING, new_version->status());
1990
1991 // Shutdown.
1992 update_helper_->context()->wrapper()->Shutdown();
1993 auto* embedded_worker_instance_client =
1994 update_helper_->AddNewPendingInstanceClient<
1995 UpdateJobTestHelper::ScriptFailureEmbeddedWorkerInstanceClient>(
1996 update_helper_);
1997 update_helper_->AddNewPendingServiceWorker<
1998 UpdateJobTestHelper::ScriptFailureServiceWorker>(
1999 update_helper_, embedded_worker_instance_client);
2000
2001 // Allow the activation to continue. It will fail, and the worker
2002 // should not be promoted to ACTIVATED because failure occur
2003 // during shutdown.
2004 runner->RunPendingTasks();
2005 base::RunLoop().RunUntilIdle();
2006 EXPECT_EQ(new_version.get(), registration->active_version());
2007 EXPECT_EQ(ServiceWorkerVersion::ACTIVATING, new_version->status());
2008 registration->RemoveListener(update_helper_);
2009 // Dispatch Mojo messages for those Mojo interfaces bound on |runner| to
2010 // avoid possible memory leak.
2011 runner->RunUntilIdle();
2012 }
2013
2014 class ServiceWorkerUpdateJobTestWithCrossOriginIsolation
2015 : public ServiceWorkerUpdateJobTest {
2016 public:
ServiceWorkerUpdateJobTestWithCrossOriginIsolation()2017 ServiceWorkerUpdateJobTestWithCrossOriginIsolation() {
2018 feature_list_.InitAndEnableFeature(
2019 ::network::features::kCrossOriginEmbedderPolicy);
2020 }
2021
2022 private:
2023 base::test::ScopedFeatureList feature_list_;
2024 };
2025
2026 // Update job should handle the COEP header appropriately.
TEST_F(ServiceWorkerUpdateJobTestWithCrossOriginIsolation,Update_CrossOriginEmbedderPolicyValue)2027 TEST_F(ServiceWorkerUpdateJobTestWithCrossOriginIsolation,
2028 Update_CrossOriginEmbedderPolicyValue) {
2029 const GURL kNewVersionOrigin("https://newversion/");
2030 const char kHeadersWithRequireCorp[] = R"(HTTP/1.1 200 OK
2031 Content-Type: application/javascript
2032 Cross-Origin-Embedder-Policy: require-corp
2033
2034 )";
2035 const char kHeadersWithNone[] = R"(HTTP/1.1 200 OK
2036 Content-Type: application/javascript
2037 Cross-Origin-Embedder-Policy: none
2038
2039 )";
2040
2041 const base::Time kToday = base::Time::Now();
2042 const base::Time kYesterday =
2043 kToday - base::TimeDelta::FromDays(1) - base::TimeDelta::FromHours(1);
2044
2045 scoped_refptr<ServiceWorkerRegistration> registration =
2046 update_helper_->SetupInitialRegistration(kNewVersionOrigin);
2047 ASSERT_TRUE(registration.get());
2048 EXPECT_FALSE(registration->active_version()->cross_origin_embedder_policy());
2049
2050 registration->AddListener(update_helper_);
2051
2052 // Run an update where the response header is updated but the script did not
2053 // change. No update is found but the last update check time is updated.
2054 update_helper_->fake_network_.SetResponse(kNewVersionOrigin.Resolve(kScript),
2055 kHeadersWithRequireCorp, kBody,
2056 /*network_accessed=*/true, net::OK);
2057
2058 {
2059 base::HistogramTester histogram_tester;
2060 registration->set_last_update_check(kYesterday);
2061 registration->active_version()->StartUpdate();
2062 base::RunLoop().RunUntilIdle();
2063 EXPECT_LT(kYesterday, registration->last_update_check());
2064 EXPECT_FALSE(update_helper_->update_found_);
2065 }
2066
2067 // Run an update where the COEP value and the script changed.
2068 update_helper_->fake_network_.SetResponse(kNewVersionOrigin.Resolve(kScript),
2069 kHeadersWithRequireCorp, kNewBody,
2070 /*network_accessed=*/true, net::OK);
2071 {
2072 base::HistogramTester histogram_tester;
2073 registration->set_last_update_check(kYesterday);
2074 registration->active_version()->StartUpdate();
2075 base::RunLoop().RunUntilIdle();
2076 EXPECT_LT(kYesterday, registration->last_update_check());
2077 EXPECT_TRUE(update_helper_->update_found_);
2078 ASSERT_NE(nullptr, registration->waiting_version());
2079 EXPECT_EQ(CrossOriginEmbedderPolicyRequireCorp(),
2080 registration->waiting_version()->cross_origin_embedder_policy());
2081 }
2082
2083 // Run an update again where the COEP value and the body has been updated. The
2084 // COEP value should be updated appropriately.
2085 update_helper_->fake_network_.SetResponse(kNewVersionOrigin.Resolve(kScript),
2086 kHeadersWithNone, kBody,
2087 /*network_accessed=*/true, net::OK);
2088 {
2089 base::HistogramTester histogram_tester;
2090 registration->set_last_update_check(kYesterday);
2091 registration->active_version()->StartUpdate();
2092 base::RunLoop().RunUntilIdle();
2093 EXPECT_LT(kYesterday, registration->last_update_check());
2094 EXPECT_TRUE(update_helper_->update_found_);
2095 ASSERT_NE(nullptr, registration->waiting_version());
2096 EXPECT_EQ(CrossOriginEmbedderPolicyNone(),
2097 registration->waiting_version()->cross_origin_embedder_policy());
2098 }
2099 }
2100
2101 class WaitForeverInstallWorker : public FakeServiceWorker {
2102 public:
WaitForeverInstallWorker(EmbeddedWorkerTestHelper * helper)2103 WaitForeverInstallWorker(EmbeddedWorkerTestHelper* helper)
2104 : FakeServiceWorker(helper) {}
2105 ~WaitForeverInstallWorker() override = default;
2106
DispatchInstallEvent(blink::mojom::ServiceWorker::DispatchInstallEventCallback callback)2107 void DispatchInstallEvent(
2108 blink::mojom::ServiceWorker::DispatchInstallEventCallback callback)
2109 override {
2110 callback_ = std::move(callback);
2111 }
2112
2113 private:
2114 blink::mojom::ServiceWorker::DispatchInstallEventCallback callback_;
2115 };
2116
2117 // Test that the job queue doesn't get stuck by bad workers.
TEST_F(ServiceWorkerJobTest,TimeoutBadJobs)2118 TEST_F(ServiceWorkerJobTest, TimeoutBadJobs) {
2119 blink::mojom::ServiceWorkerRegistrationOptions options;
2120 options.scope = GURL("https://www.example.com/");
2121
2122 // Make a job that gets stuck due to a worker stalled in starting.
2123 base::RunLoop loop1;
2124 scoped_refptr<ServiceWorkerRegistration> registration1;
2125 helper_->AddPendingInstanceClient(
2126 std::make_unique<DelayedFakeEmbeddedWorkerInstanceClient>(helper_.get()));
2127 job_coordinator()->Register(
2128 GURL("https://www.example.com/service_worker1.js"), options,
2129 blink::mojom::FetchClientSettingsObject::New(),
2130 SaveRegistration(blink::ServiceWorkerStatusCode::kErrorTimeout,
2131 ®istration1, loop1.QuitClosure()));
2132
2133 task_environment_.FastForwardBy(base::TimeDelta::FromMinutes(1));
2134
2135 // Make a job that gets stuck due to a worker that doesn't finish the install
2136 // event. The callback is called with kOk, but the job will be stuck until
2137 // the install event times out.
2138 base::RunLoop loop2;
2139 helper_->AddPendingServiceWorker(
2140 std::make_unique<WaitForeverInstallWorker>(helper_.get()));
2141 scoped_refptr<ServiceWorkerRegistration> registration2;
2142 job_coordinator()->Register(
2143 GURL("https://www.example.com/service_worker2.js"), options,
2144 blink::mojom::FetchClientSettingsObject::New(),
2145 SaveRegistration(blink::ServiceWorkerStatusCode::kOk, ®istration2,
2146 loop2.QuitClosure()));
2147
2148 task_environment_.FastForwardBy(base::TimeDelta::FromMinutes(1));
2149
2150 // Make a normal job.
2151 base::RunLoop loop3;
2152 scoped_refptr<ServiceWorkerRegistration> registration3;
2153 job_coordinator()->Register(
2154 GURL("https://www.example.com/service_worker3.js"), options,
2155 blink::mojom::FetchClientSettingsObject::New(),
2156 SaveRegistration(blink::ServiceWorkerStatusCode::kOk, ®istration3,
2157 loop3.QuitClosure()));
2158
2159 task_environment_.FastForwardBy(base::TimeDelta::FromMinutes(1));
2160
2161 // Timeout the first job.
2162 task_environment_.FastForwardBy(base::TimeDelta::FromMinutes(2));
2163 loop1.Run();
2164
2165 // Let the second job run until the install event is dispatched, then
2166 // time out the event.
2167 loop2.Run();
2168 scoped_refptr<ServiceWorkerVersion> version =
2169 registration2->installing_version();
2170 ASSERT_TRUE(version);
2171 EXPECT_EQ(ServiceWorkerVersion::INSTALLING, version->status());
2172 task_environment_.FastForwardBy(base::TimeDelta::FromMinutes(5));
2173 EXPECT_EQ(ServiceWorkerVersion::REDUNDANT, version->status());
2174
2175 // Let the third job finish successfully. It might have already been
2176 // progressing so we don't know what state its worker is in, but it will
2177 // eventually reach ACTIVATED.
2178 loop3.Run();
2179 version = registration3->GetNewestVersion();
2180 ASSERT_TRUE(version);
2181 TestServiceWorkerObserver observer(helper_->context_wrapper());
2182 observer.RunUntilStatusChange(version.get(), ServiceWorkerVersion::ACTIVATED);
2183 }
2184
2185 } // namespace content
2186