| // Copyright 2017 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "content/renderer/service_worker/service_worker_context_client.h" |
| |
| #include <utility> |
| #include <vector> |
| |
| #include "base/message_loop/message_loop.h" |
| #include "base/run_loop.h" |
| #include "base/test/scoped_feature_list.h" |
| #include "base/test/test_mock_time_task_runner.h" |
| #include "base/time/tick_clock.h" |
| #include "base/time/time.h" |
| #include "content/child/thread_safe_sender.h" |
| #include "content/renderer/service_worker/embedded_worker_instance_client_impl.h" |
| #include "content/renderer/service_worker/service_worker_timeout_timer.h" |
| #include "content/renderer/service_worker/web_service_worker_impl.h" |
| #include "content/renderer/worker_thread_registry.h" |
| #include "mojo/public/cpp/bindings/associated_binding_set.h" |
| #include "mojo/public/cpp/bindings/associated_interface_ptr.h" |
| #include "services/network/public/cpp/features.h" |
| #include "services/network/public/cpp/resource_request.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/blink/public/common/message_port/message_port_channel.h" |
| #include "third_party/blink/public/common/service_worker/service_worker_utils.h" |
| #include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom.h" |
| #include "third_party/blink/public/platform/modules/background_fetch/web_background_fetch_settled_fetch.h" |
| #include "third_party/blink/public/platform/modules/notifications/web_notification_data.h" |
| #include "third_party/blink/public/platform/modules/payments/web_payment_request_event_data.h" |
| #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_clients_info.h" |
| #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_error.h" |
| #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_request.h" |
| #include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h" |
| #include "third_party/blink/public/platform/web_data_consumer_handle.h" |
| #include "third_party/blink/public/platform/web_string.h" |
| #include "third_party/blink/public/platform/web_url_response.h" |
| #include "third_party/blink/public/web/modules/service_worker/web_service_worker_context_proxy.h" |
| |
| namespace content { |
| |
| namespace { |
| |
| // Pipes connected to the context client. |
| struct ContextClientPipes { |
| // From the browser to ServiceWorkerContextClient. |
| mojom::ServiceWorkerEventDispatcherPtr event_dispatcher; |
| mojom::ControllerServiceWorkerPtr controller; |
| blink::mojom::ServiceWorkerRegistrationObjectAssociatedPtr registration; |
| |
| // From ServiceWorkerContextClient to the browser. |
| blink::mojom::ServiceWorkerHostAssociatedRequest service_worker_host_request; |
| mojom::EmbeddedWorkerInstanceHostAssociatedRequest |
| embedded_worker_host_request; |
| blink::mojom::ServiceWorkerRegistrationObjectHostAssociatedRequest |
| registration_host_request; |
| }; |
| |
| class MockWebServiceWorkerContextProxy |
| : public blink::WebServiceWorkerContextProxy { |
| public: |
| ~MockWebServiceWorkerContextProxy() override = default; |
| |
| void ReadyToEvaluateScript() override {} |
| void SetRegistration( |
| std::unique_ptr<blink::WebServiceWorkerRegistration::Handle> handle) |
| override { |
| registration_handle_ = std::move(handle); |
| } |
| bool HasFetchEventHandler() override { return false; } |
| void DispatchFetchEvent(int fetch_event_id, |
| const blink::WebServiceWorkerRequest& web_request, |
| bool navigation_preload_sent) override { |
| fetch_events_.emplace_back(fetch_event_id, web_request); |
| } |
| |
| void DispatchActivateEvent(int event_id) override { NOTREACHED(); } |
| void DispatchBackgroundFetchAbortEvent( |
| int event_id, |
| const blink::WebString& developer_id, |
| const blink::WebString& unique_id, |
| const blink::WebVector<blink::WebBackgroundFetchSettledFetch>& fetches) |
| override { |
| NOTREACHED(); |
| } |
| void DispatchBackgroundFetchClickEvent(int event_id, |
| const blink::WebString& developer_id, |
| BackgroundFetchState status) override { |
| NOTREACHED(); |
| } |
| void DispatchBackgroundFetchFailEvent( |
| int event_id, |
| const blink::WebString& developer_id, |
| const blink::WebString& unique_id, |
| const blink::WebVector<blink::WebBackgroundFetchSettledFetch>& fetches) |
| override { |
| NOTREACHED(); |
| } |
| void DispatchBackgroundFetchedEvent( |
| int event_id, |
| const blink::WebString& developer_id, |
| const blink::WebString& unique_id, |
| const blink::WebVector<blink::WebBackgroundFetchSettledFetch>& fetches) |
| override { |
| NOTREACHED(); |
| } |
| void DispatchCookieChangeEvent( |
| int event_id, |
| const blink::WebCanonicalCookie& cookie, |
| ::network::mojom::CookieChangeCause change_cause) override { |
| NOTREACHED(); |
| } |
| void DispatchExtendableMessageEvent( |
| int event_id, |
| blink::TransferableMessage message, |
| const blink::WebSecurityOrigin& source_origin, |
| const blink::WebServiceWorkerClientInfo&) override { |
| NOTREACHED(); |
| } |
| void DispatchExtendableMessageEvent( |
| int event_id, |
| blink::TransferableMessage message, |
| const blink::WebSecurityOrigin& source_origin, |
| std::unique_ptr<blink::WebServiceWorker::Handle>) override { |
| NOTREACHED(); |
| } |
| void DispatchInstallEvent(int event_id) override { NOTREACHED(); } |
| void DispatchNotificationClickEvent(int event_id, |
| const blink::WebString& notification_id, |
| const blink::WebNotificationData&, |
| int action_index, |
| const blink::WebString& reply) override { |
| NOTREACHED(); |
| } |
| void DispatchNotificationCloseEvent( |
| int event_id, |
| const blink::WebString& notification_id, |
| const blink::WebNotificationData&) override { |
| NOTREACHED(); |
| } |
| void DispatchPushEvent(int event_id, const blink::WebString& data) override { |
| NOTREACHED(); |
| } |
| void DispatchSyncEvent(int sync_event_id, |
| const blink::WebString& tag, |
| bool last_chance) override { |
| NOTREACHED(); |
| } |
| void DispatchAbortPaymentEvent(int event_id) override { NOTREACHED(); } |
| void DispatchCanMakePaymentEvent( |
| int event_id, |
| const blink::WebCanMakePaymentEventData&) override { |
| NOTREACHED(); |
| } |
| void DispatchPaymentRequestEvent( |
| int event_id, |
| const blink::WebPaymentRequestEventData&) override { |
| NOTREACHED(); |
| } |
| void OnNavigationPreloadResponse( |
| int fetch_event_id, |
| std::unique_ptr<blink::WebURLResponse>, |
| std::unique_ptr<blink::WebDataConsumerHandle>) override { |
| NOTREACHED(); |
| } |
| void OnNavigationPreloadError( |
| int fetch_event_id, |
| std::unique_ptr<blink::WebServiceWorkerError>) override { |
| NOTREACHED(); |
| } |
| void OnNavigationPreloadComplete(int fetch_event_id, |
| base::TimeTicks completion_time, |
| int64_t encoded_data_length, |
| int64_t encoded_body_length, |
| int64_t decoded_body_length) override { |
| NOTREACHED(); |
| } |
| |
| const std::vector< |
| std::pair<int /* event_id */, blink::WebServiceWorkerRequest>>& |
| fetch_events() const { |
| return fetch_events_; |
| } |
| |
| private: |
| std::unique_ptr<blink::WebServiceWorkerRegistration::Handle> |
| registration_handle_; |
| std::vector<std::pair<int /* event_id */, blink::WebServiceWorkerRequest>> |
| fetch_events_; |
| }; |
| |
| base::RepeatingClosure CreateCallbackWithCalledFlag(bool* out_is_called) { |
| return base::BindRepeating([](bool* out_is_called) { *out_is_called = true; }, |
| out_is_called); |
| } |
| |
| class MockServiceWorkerObjectHost |
| : public blink::mojom::ServiceWorkerObjectHost { |
| public: |
| explicit MockServiceWorkerObjectHost(int64_t version_id) |
| : version_id_(version_id) {} |
| ~MockServiceWorkerObjectHost() override = default; |
| |
| blink::mojom::ServiceWorkerObjectInfoPtr CreateObjectInfo() { |
| auto info = blink::mojom::ServiceWorkerObjectInfo::New(); |
| info->version_id = version_id_; |
| bindings_.AddBinding(this, mojo::MakeRequest(&info->host_ptr_info)); |
| info->request = mojo::MakeRequest(&remote_object_); |
| return info; |
| } |
| |
| int GetBindingCount() const { return bindings_.size(); } |
| |
| private: |
| // Implements blink::mojom::ServiceWorkerObjectHost. |
| void PostMessageToServiceWorker( |
| ::blink::TransferableMessage message) override { |
| NOTREACHED(); |
| } |
| void TerminateForTesting(TerminateForTestingCallback callback) override { |
| NOTREACHED(); |
| } |
| |
| const int64_t version_id_; |
| mojo::AssociatedBindingSet<blink::mojom::ServiceWorkerObjectHost> bindings_; |
| blink::mojom::ServiceWorkerObjectAssociatedPtr remote_object_; |
| }; |
| |
| } // namespace |
| |
| class ServiceWorkerContextClientTest : public testing::Test { |
| public: |
| ServiceWorkerContextClientTest() = default; |
| |
| protected: |
| void SetUp() override { |
| task_runner_ = base::MakeRefCounted<base::TestMockTimeTaskRunner>(); |
| message_loop_.SetTaskRunner(task_runner_); |
| // Use this thread as the worker thread. |
| WorkerThreadRegistry::Instance()->DidStartCurrentWorkerThread(); |
| } |
| |
| void TearDown() override { |
| ServiceWorkerContextClient::ResetThreadSpecificInstanceForTesting(); |
| // Unregister this thread from worker threads. |
| WorkerThreadRegistry::Instance()->WillStopCurrentWorkerThread(); |
| task_runner_->RunUntilIdle(); |
| } |
| |
| void EnableServicification() { |
| feature_list_.InitWithFeatures({network::features::kNetworkService}, {}); |
| ASSERT_TRUE(blink::ServiceWorkerUtils::IsServicificationEnabled()); |
| } |
| |
| // Creates an empty struct to initialize ServiceWorkerProviderContext. |
| mojom::ServiceWorkerProviderInfoForStartWorkerPtr CreateProviderInfo() { |
| auto info = mojom::ServiceWorkerProviderInfoForStartWorker::New(); |
| info->provider_id = 10; // dummy |
| return info; |
| } |
| |
| // Creates an ContextClient, whose pipes are connected to |out_pipes|, then |
| // simulates that the service worker thread has started with |proxy|. |
| std::unique_ptr<ServiceWorkerContextClient> CreateContextClient( |
| ContextClientPipes* out_pipes, |
| blink::WebServiceWorkerContextProxy* proxy) { |
| auto event_dispatcher_request = |
| mojo::MakeRequest(&out_pipes->event_dispatcher); |
| auto controller_request = mojo::MakeRequest(&out_pipes->controller); |
| mojom::EmbeddedWorkerInstanceHostAssociatedPtr embedded_worker_host_ptr; |
| out_pipes->embedded_worker_host_request = |
| mojo::MakeRequestAssociatedWithDedicatedPipe(&embedded_worker_host_ptr); |
| const GURL kScope("https://example.com"); |
| const GURL kScript("https://example.com/SW.js"); |
| std::unique_ptr<ServiceWorkerContextClient> context_client = |
| std::make_unique<ServiceWorkerContextClient>( |
| 1 /* embedded_worker_id */, 1 /* service_worker_version_id */, |
| kScope, kScript, false /* is_script_streaming */, |
| std::move(event_dispatcher_request), std::move(controller_request), |
| embedded_worker_host_ptr.PassInterface(), CreateProviderInfo(), |
| nullptr /* embedded_worker_client */, |
| mojom::EmbeddedWorkerStartTiming::New(), |
| blink::scheduler::GetSingleThreadTaskRunnerForTesting()); |
| |
| context_client->WorkerContextStarted(proxy); |
| |
| blink::mojom::ServiceWorkerHostAssociatedPtrInfo service_worker_host; |
| out_pipes->service_worker_host_request = |
| mojo::MakeRequest(&service_worker_host); |
| auto registration_info = |
| blink::mojom::ServiceWorkerRegistrationObjectInfo::New(); |
| registration_info->registration_id = 100; // dummy |
| registration_info->options = |
| blink::mojom::ServiceWorkerRegistrationOptions::New( |
| kScope, blink::mojom::ServiceWorkerUpdateViaCache::kAll); |
| out_pipes->registration_host_request = |
| mojo::MakeRequest(®istration_info->host_ptr_info); |
| registration_info->request = mojo::MakeRequest(&out_pipes->registration); |
| out_pipes->event_dispatcher->InitializeGlobalScope( |
| std::move(service_worker_host), std::move(registration_info)); |
| task_runner()->RunUntilIdle(); |
| return context_client; |
| } |
| |
| bool ContainsServiceWorkerObject(ServiceWorkerContextClient* context_client, |
| int64_t version_id) { |
| return context_client->ContainsServiceWorkerObjectForTesting(version_id); |
| } |
| |
| scoped_refptr<base::TestMockTimeTaskRunner> task_runner() const { |
| return task_runner_; |
| } |
| |
| private: |
| base::MessageLoop message_loop_; |
| scoped_refptr<base::TestMockTimeTaskRunner> task_runner_; |
| base::test::ScopedFeatureList feature_list_; |
| }; |
| |
| TEST_F(ServiceWorkerContextClientTest, Ping) { |
| ContextClientPipes pipes; |
| MockWebServiceWorkerContextProxy mock_proxy; |
| std::unique_ptr<ServiceWorkerContextClient> context_client = |
| CreateContextClient(&pipes, &mock_proxy); |
| |
| bool is_called = false; |
| pipes.event_dispatcher->Ping(CreateCallbackWithCalledFlag(&is_called)); |
| task_runner()->RunUntilIdle(); |
| EXPECT_TRUE(is_called); |
| } |
| |
| TEST_F(ServiceWorkerContextClientTest, DispatchFetchEvent) { |
| ContextClientPipes pipes; |
| MockWebServiceWorkerContextProxy mock_proxy; |
| std::unique_ptr<ServiceWorkerContextClient> context_client = |
| CreateContextClient(&pipes, &mock_proxy); |
| context_client->DidEvaluateClassicScript(true /* success */); |
| task_runner()->RunUntilIdle(); |
| EXPECT_TRUE(mock_proxy.fetch_events().empty()); |
| |
| const GURL expected_url("https://example.com/expected"); |
| mojom::ServiceWorkerFetchResponseCallbackRequest fetch_callback_request; |
| auto request = std::make_unique<network::ResourceRequest>(); |
| request->url = expected_url; |
| mojom::ServiceWorkerFetchResponseCallbackPtr fetch_callback_ptr; |
| fetch_callback_request = mojo::MakeRequest(&fetch_callback_ptr); |
| auto params = blink::mojom::DispatchFetchEventParams::New(); |
| params->request = *request; |
| pipes.event_dispatcher->DispatchFetchEvent( |
| std::move(params), std::move(fetch_callback_ptr), |
| base::BindOnce( |
| [](blink::mojom::ServiceWorkerEventStatus, base::Time) {})); |
| task_runner()->RunUntilIdle(); |
| |
| ASSERT_EQ(1u, mock_proxy.fetch_events().size()); |
| EXPECT_EQ(request->url, |
| static_cast<GURL>(mock_proxy.fetch_events()[0].second.Url())); |
| } |
| |
| TEST_F(ServiceWorkerContextClientTest, |
| DispatchOrQueueFetchEvent_NotRequestedTermination) { |
| EnableServicification(); |
| ContextClientPipes pipes; |
| MockWebServiceWorkerContextProxy mock_proxy; |
| std::unique_ptr<ServiceWorkerContextClient> context_client = |
| CreateContextClient(&pipes, &mock_proxy); |
| context_client->DidEvaluateClassicScript(true /* success */); |
| task_runner()->RunUntilIdle(); |
| EXPECT_TRUE(mock_proxy.fetch_events().empty()); |
| |
| bool is_idle = false; |
| auto timer = std::make_unique<ServiceWorkerTimeoutTimer>( |
| CreateCallbackWithCalledFlag(&is_idle), |
| task_runner()->GetMockTickClock()); |
| context_client->SetTimeoutTimerForTesting(std::move(timer)); |
| |
| // The dispatched fetch event should be recorded by |mock_proxy|. |
| const GURL expected_url("https://example.com/expected"); |
| mojom::ServiceWorkerFetchResponseCallbackPtr fetch_callback_ptr; |
| mojom::ServiceWorkerFetchResponseCallbackRequest fetch_callback_request = |
| mojo::MakeRequest(&fetch_callback_ptr); |
| auto request = std::make_unique<network::ResourceRequest>(); |
| request->url = expected_url; |
| auto params = blink::mojom::DispatchFetchEventParams::New(); |
| params->request = *request; |
| context_client->DispatchOrQueueFetchEvent( |
| std::move(params), std::move(fetch_callback_ptr), |
| base::BindOnce( |
| [](blink::mojom::ServiceWorkerEventStatus, base::Time) {})); |
| task_runner()->RunUntilIdle(); |
| |
| EXPECT_FALSE(context_client->RequestedTermination()); |
| ASSERT_EQ(1u, mock_proxy.fetch_events().size()); |
| EXPECT_EQ(expected_url, |
| static_cast<GURL>(mock_proxy.fetch_events()[0].second.Url())); |
| } |
| |
| TEST_F(ServiceWorkerContextClientTest, |
| DispatchOrQueueFetchEvent_RequestedTerminationAndDie) { |
| EnableServicification(); |
| ContextClientPipes pipes; |
| MockWebServiceWorkerContextProxy mock_proxy; |
| std::unique_ptr<ServiceWorkerContextClient> context_client = |
| CreateContextClient(&pipes, &mock_proxy); |
| context_client->DidEvaluateClassicScript(true /* success */); |
| task_runner()->RunUntilIdle(); |
| EXPECT_TRUE(mock_proxy.fetch_events().empty()); |
| |
| bool is_idle = false; |
| auto timer = std::make_unique<ServiceWorkerTimeoutTimer>( |
| CreateCallbackWithCalledFlag(&is_idle), |
| task_runner()->GetMockTickClock()); |
| context_client->SetTimeoutTimerForTesting(std::move(timer)); |
| |
| // Ensure the idle state. |
| EXPECT_FALSE(context_client->RequestedTermination()); |
| task_runner()->FastForwardBy(ServiceWorkerTimeoutTimer::kIdleDelay + |
| ServiceWorkerTimeoutTimer::kUpdateInterval + |
| base::TimeDelta::FromSeconds(1)); |
| EXPECT_TRUE(context_client->RequestedTermination()); |
| |
| const GURL expected_url("https://example.com/expected"); |
| mojom::ServiceWorkerFetchResponseCallbackRequest fetch_callback_request; |
| |
| // FetchEvent dispatched directly from the controlled clients through |
| // mojom::ControllerServiceWorker should be queued in the idle state. |
| { |
| mojom::ServiceWorkerFetchResponseCallbackPtr fetch_callback_ptr; |
| fetch_callback_request = mojo::MakeRequest(&fetch_callback_ptr); |
| auto request = std::make_unique<network::ResourceRequest>(); |
| request->url = expected_url; |
| auto params = blink::mojom::DispatchFetchEventParams::New(); |
| params->request = *request; |
| pipes.controller->DispatchFetchEvent( |
| std::move(params), std::move(fetch_callback_ptr), |
| base::BindOnce( |
| [](blink::mojom::ServiceWorkerEventStatus, base::Time) {})); |
| task_runner()->RunUntilIdle(); |
| } |
| EXPECT_TRUE(mock_proxy.fetch_events().empty()); |
| |
| // Destruction of |context_client| should not hit any DCHECKs. |
| context_client.reset(); |
| } |
| |
| TEST_F(ServiceWorkerContextClientTest, |
| DispatchOrQueueFetchEvent_RequestedTerminationAndWakeUp) { |
| EnableServicification(); |
| ContextClientPipes pipes; |
| MockWebServiceWorkerContextProxy mock_proxy; |
| std::unique_ptr<ServiceWorkerContextClient> context_client = |
| CreateContextClient(&pipes, &mock_proxy); |
| context_client->DidEvaluateClassicScript(true /* success */); |
| task_runner()->RunUntilIdle(); |
| EXPECT_TRUE(mock_proxy.fetch_events().empty()); |
| bool is_idle = false; |
| auto timer = std::make_unique<ServiceWorkerTimeoutTimer>( |
| CreateCallbackWithCalledFlag(&is_idle), |
| task_runner()->GetMockTickClock()); |
| context_client->SetTimeoutTimerForTesting(std::move(timer)); |
| |
| // Ensure the idle state. |
| EXPECT_FALSE(context_client->RequestedTermination()); |
| task_runner()->FastForwardBy(ServiceWorkerTimeoutTimer::kIdleDelay + |
| ServiceWorkerTimeoutTimer::kUpdateInterval + |
| base::TimeDelta::FromSeconds(1)); |
| EXPECT_TRUE(context_client->RequestedTermination()); |
| |
| const GURL expected_url_1("https://example.com/expected_1"); |
| const GURL expected_url_2("https://example.com/expected_2"); |
| mojom::ServiceWorkerFetchResponseCallbackRequest fetch_callback_request_1; |
| mojom::ServiceWorkerFetchResponseCallbackRequest fetch_callback_request_2; |
| |
| // FetchEvent dispatched directly from the controlled clients through |
| // mojom::ControllerServiceWorker should be queued in the idle state. |
| { |
| mojom::ServiceWorkerFetchResponseCallbackPtr fetch_callback_ptr; |
| fetch_callback_request_1 = mojo::MakeRequest(&fetch_callback_ptr); |
| auto request = std::make_unique<network::ResourceRequest>(); |
| request->url = expected_url_1; |
| auto params = blink::mojom::DispatchFetchEventParams::New(); |
| params->request = *request; |
| pipes.controller->DispatchFetchEvent( |
| std::move(params), std::move(fetch_callback_ptr), |
| base::BindOnce( |
| [](blink::mojom::ServiceWorkerEventStatus, base::Time) {})); |
| task_runner()->RunUntilIdle(); |
| } |
| EXPECT_TRUE(mock_proxy.fetch_events().empty()); |
| |
| // Another event dispatched to mojom::ServiceWorkerEventDispatcher wakes up |
| // the context client. |
| { |
| mojom::ServiceWorkerFetchResponseCallbackPtr fetch_callback_ptr; |
| fetch_callback_request_2 = mojo::MakeRequest(&fetch_callback_ptr); |
| auto request = std::make_unique<network::ResourceRequest>(); |
| request->url = expected_url_2; |
| auto params = blink::mojom::DispatchFetchEventParams::New(); |
| params->request = *request; |
| pipes.event_dispatcher->DispatchFetchEvent( |
| std::move(params), std::move(fetch_callback_ptr), |
| base::BindOnce( |
| [](blink::mojom::ServiceWorkerEventStatus, base::Time) {})); |
| task_runner()->RunUntilIdle(); |
| } |
| EXPECT_FALSE(context_client->RequestedTermination()); |
| |
| // All events should fire. The order of events should be kept. |
| ASSERT_EQ(2u, mock_proxy.fetch_events().size()); |
| EXPECT_EQ(expected_url_1, |
| static_cast<GURL>(mock_proxy.fetch_events()[0].second.Url())); |
| EXPECT_EQ(expected_url_2, |
| static_cast<GURL>(mock_proxy.fetch_events()[1].second.Url())); |
| } |
| |
| TEST_F(ServiceWorkerContextClientTest, GetOrCreateServiceWorkerObject) { |
| ContextClientPipes pipes; |
| MockWebServiceWorkerContextProxy mock_proxy; |
| std::unique_ptr<ServiceWorkerContextClient> context_client = |
| CreateContextClient(&pipes, &mock_proxy); |
| scoped_refptr<WebServiceWorkerImpl> worker1; |
| scoped_refptr<WebServiceWorkerImpl> worker2; |
| const int64_t version_id = 200; |
| auto mock_service_worker_object_host = |
| std::make_unique<MockServiceWorkerObjectHost>(version_id); |
| ASSERT_EQ(0, mock_service_worker_object_host->GetBindingCount()); |
| |
| // Should return a worker object newly created with the 1st given |info|. |
| { |
| blink::mojom::ServiceWorkerObjectInfoPtr info = |
| mock_service_worker_object_host->CreateObjectInfo(); |
| // ServiceWorkerObjectHost Mojo connection has been added. |
| EXPECT_EQ(1, mock_service_worker_object_host->GetBindingCount()); |
| EXPECT_FALSE(ContainsServiceWorkerObject(context_client.get(), version_id)); |
| worker1 = context_client->GetOrCreateServiceWorkerObject(std::move(info)); |
| EXPECT_TRUE(worker1); |
| EXPECT_TRUE(ContainsServiceWorkerObject(context_client.get(), version_id)); |
| // |worker1| is holding the 1st blink::mojom::ServiceWorkerObjectHost Mojo |
| // connection to |mock_service_worker_object_host|. |
| EXPECT_EQ(1, mock_service_worker_object_host->GetBindingCount()); |
| } |
| |
| // Should return the same worker object and release the 2nd given |info|. |
| { |
| blink::mojom::ServiceWorkerObjectInfoPtr info = |
| mock_service_worker_object_host->CreateObjectInfo(); |
| EXPECT_EQ(2, mock_service_worker_object_host->GetBindingCount()); |
| worker2 = context_client->GetOrCreateServiceWorkerObject(std::move(info)); |
| EXPECT_EQ(worker1, worker2); |
| task_runner()->RunUntilIdle(); |
| // The 2nd ServiceWorkerObjectHost Mojo connection in |info| has been |
| // dropped. |
| EXPECT_EQ(1, mock_service_worker_object_host->GetBindingCount()); |
| } |
| |
| // The dtor decrements the refcounts. |
| worker1 = nullptr; |
| worker2 = nullptr; |
| task_runner()->RunUntilIdle(); |
| EXPECT_FALSE(ContainsServiceWorkerObject(context_client.get(), version_id)); |
| // The 1st ServiceWorkerObjectHost Mojo connection got broken. |
| EXPECT_EQ(0, mock_service_worker_object_host->GetBindingCount()); |
| |
| // Should return nullptr when given nullptr. |
| scoped_refptr<WebServiceWorkerImpl> invalid_worker = |
| context_client->GetOrCreateServiceWorkerObject(nullptr); |
| EXPECT_FALSE(invalid_worker); |
| } |
| |
| } // namespace content |