chromium/content/browser/service_worker/service_worker_job_unittest.cc

// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <stdint.h>

#include <memory>
#include <optional>
#include <tuple>

#include "base/barrier_closure.h"
#include "base/check.h"
#include "base/files/scoped_temp_dir.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/test_future.h"
#include "base/test/test_simple_task_runner.h"
#include "base/time/time.h"
#include "components/services/storage/service_worker/service_worker_database.h"
#include "content/browser/renderer_host/frame_tree_node.h"
#include "content/browser/service_worker/embedded_worker_test_helper.h"
#include "content/browser/service_worker/fake_embedded_worker_instance_client.h"
#include "content/browser/service_worker/service_worker_client.h"
#include "content/browser/service_worker/service_worker_consts.h"
#include "content/browser/service_worker/service_worker_container_host.h"
#include "content/browser/service_worker/service_worker_context_core.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/browser/service_worker/service_worker_job_coordinator.h"
#include "content/browser/service_worker/service_worker_object_host.h"
#include "content/browser/service_worker/service_worker_registration.h"
#include "content/browser/service_worker/service_worker_registration_object_host.h"
#include "content/browser/service_worker/service_worker_registration_status.h"
#include "content/browser/service_worker/service_worker_test_utils.h"
#include "content/browser/service_worker/test_service_worker_observer.h"
#include "content/browser/storage_partition_impl.h"
#include "content/public/test/browser_task_environment.h"
#include "content/public/test/test_browser_context.h"
#include "content/public/test/url_loader_interceptor.h"
#include "content/test/fake_network.h"
#include "content/test/storage_partition_test_helpers.h"
#include "ipc/ipc_test_sink.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/base/test_completion_callback.h"
#include "net/http/http_response_headers.h"
#include "services/network/public/cpp/features.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/common/service_worker/embedded_worker_status.h"
#include "third_party/blink/public/common/storage_key/storage_key.h"
#include "third_party/blink/public/mojom/service_worker/embedded_worker.mojom.h"
#include "third_party/blink/public/mojom/service_worker/service_worker.mojom.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_event_status.mojom.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_object.mojom.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_registration_options.mojom.h"
#include "url/origin.h"

// Unit tests for testing all job registration tasks.
namespace content {

namespace {

IOBuffer;
TestCompletionCallback;
WrappedIOBuffer;

Eq;
Pointee;

void SaveRegistrationCallback(
    blink::ServiceWorkerStatusCode expected_status,
    scoped_refptr<ServiceWorkerRegistration>* registration_out,
    base::OnceClosure quit_closure,
    blink::ServiceWorkerStatusCode status,
    const std::string& status_message,
    ServiceWorkerRegistration* registration) {}

void SaveFoundRegistrationCallback(
    blink::ServiceWorkerStatusCode expected_status,
    scoped_refptr<ServiceWorkerRegistration>* registration,
    base::OnceClosure quit_closure,
    blink::ServiceWorkerStatusCode status,
    scoped_refptr<ServiceWorkerRegistration> result) {}

// Creates a callback which keeps track of the resulting registration.
// When the callback is fired, it ensures that the resulting status
// matches the expectation.
ServiceWorkerRegisterJob::RegistrationCallback SaveRegistration(
    blink::ServiceWorkerStatusCode expected_status,
    scoped_refptr<ServiceWorkerRegistration>* registration,
    base::OnceClosure quit_closure) {}

ServiceWorkerRegistry::FindRegistrationCallback SaveFoundRegistration(
    blink::ServiceWorkerStatusCode expected_status,
    scoped_refptr<ServiceWorkerRegistration>* registration,
    base::OnceClosure quit_closure) {}

void SaveUnregistrationCallback(blink::ServiceWorkerStatusCode expected_status,
                                base::OnceClosure quit_closure,
                                int64_t registration_id,
                                blink::ServiceWorkerStatusCode status) {}

ServiceWorkerUnregisterJob::UnregistrationCallback SaveUnregistration(
    blink::ServiceWorkerStatusCode expected_status,
    base::OnceClosure quit_closure) {}

void RequestTermination(
    mojo::AssociatedRemote<blink::mojom::EmbeddedWorkerInstanceHost>* host) {}

class EmbeddedWorkerStatusObserver : public ServiceWorkerVersion::Observer {};

network::CrossOriginEmbedderPolicy CrossOriginEmbedderPolicyNone() {}

network::CrossOriginEmbedderPolicy CrossOriginEmbedderPolicyRequireCorp() {}

}  // namespace

enum class StorageKeyTestCase {};

class ServiceWorkerJobTest
    : public testing::Test,
      public testing::WithParamInterface<StorageKeyTestCase> {};

scoped_refptr<ServiceWorkerRegistration> ServiceWorkerJobTest::RunRegisterJob(
    const GURL& script_url,
    const blink::StorageKey& key,
    const blink::mojom::ServiceWorkerRegistrationOptions& options,
    blink::ServiceWorkerStatusCode expected_status) {}

void ServiceWorkerJobTest::RunUnregisterJob(
    const GURL& scope,
    const blink::StorageKey& key,
    blink::ServiceWorkerStatusCode expected_status) {}

void ServiceWorkerJobTest::WaitForVersionRunningStatus(
    scoped_refptr<ServiceWorkerVersion> version,
    blink::EmbeddedWorkerStatus running_status) {}

scoped_refptr<ServiceWorkerRegistration>
ServiceWorkerJobTest::FindRegistrationForScope(
    const GURL& scope,
    const blink::StorageKey& key,
    blink::ServiceWorkerStatusCode expected_status) {}

ServiceWorkerClient* ServiceWorkerJobTest::CreateControllee() {}

scoped_refptr<ServiceWorkerRegistration>
ServiceWorkerJobTest::CreateRegistrationWithControllee(const GURL& script_url,
                                                       const GURL& scope_url) {}

INSTANTIATE_TEST_SUITE_P();

TEST_P(ServiceWorkerJobTest, SameDocumentSameRegistration) {}

TEST_P(ServiceWorkerJobTest, SameMatchSameRegistration) {}

TEST_P(ServiceWorkerJobTest, DifferentMatchDifferentRegistration) {}

class RecordInstallActivateWorker : public FakeServiceWorker {};

// Make sure basic registration is working.
TEST_P(ServiceWorkerJobTest, Register) {}

// Make sure registrations are cleaned up when they are unregistered.
TEST_P(ServiceWorkerJobTest, Unregister) {}

TEST_P(ServiceWorkerJobTest, Unregister_NothingRegistered) {}

TEST_P(ServiceWorkerJobTest, UnregisterImmediate) {}

// Make sure registering a new script creates a new version and shares an
// existing registration.
TEST_P(ServiceWorkerJobTest, RegisterNewScript) {}

// Make sure that when registering a duplicate scope+script_url
// combination, that the same registration is used.
TEST_P(ServiceWorkerJobTest, RegisterDuplicateScript) {}

// An instance client that breaks the Mojo connection upon receiving the
// Start() message.
class FailStartInstanceClient : public FakeEmbeddedWorkerInstanceClient {};

TEST_P(ServiceWorkerJobTest, Register_FailToStartWorker) {}

// Register and then unregister the scope, in parallel. Job coordinator should
// process jobs until the last job.
TEST_P(ServiceWorkerJobTest, ParallelRegUnreg) {}

// Register conflicting scripts for the same scope. The most recent
// registration should win, and the old registration should have been
// shutdown.
TEST_P(ServiceWorkerJobTest, ParallelRegNewScript) {}

// Register the exact same scope + script. Requests should be
// coalesced such that both callers get the exact same registration
// object.
TEST_P(ServiceWorkerJobTest, ParallelRegSameScript) {}

// Call simulataneous unregister calls.
TEST_P(ServiceWorkerJobTest, ParallelUnreg) {}

TEST_P(ServiceWorkerJobTest, AbortAll_Register) {}

TEST_P(ServiceWorkerJobTest, AbortAll_Unregister) {}

TEST_P(ServiceWorkerJobTest, AbortAll_RegUnreg) {}

TEST_P(ServiceWorkerJobTest, AbortScope) {}

// Tests that the waiting worker enters the 'redundant' state upon
// unregistration.
TEST_P(ServiceWorkerJobTest, UnregisterWaitingSetsRedundant) {}

// Tests that the active worker enters the 'redundant' state upon
// unregistration.
TEST_P(ServiceWorkerJobTest, UnregisterActiveSetsRedundant) {}

// Tests that the active worker enters the 'redundant' state upon
// unregistration.
TEST_P(ServiceWorkerJobTest,
       UnregisterActiveSetsRedundant_WaitForNoControllee) {}

TEST_P(ServiceWorkerJobTest, RegisterSameWhileUninstalling) {}

TEST_P(ServiceWorkerJobTest, RegisterSameWhileUninstallingAndUnregister) {}

TEST_P(ServiceWorkerJobTest, RegisterWhileUninstalling) {}

TEST_P(ServiceWorkerJobTest, RegisterAndUnregisterWhileUninstalling) {}

TEST_P(ServiceWorkerJobTest, RegisterSameScriptMultipleTimesWhileUninstalling) {}

// Make sure that the new version is cleared up after trying to register a
// script with bad origin. (see https://crbug.com/1312995)
TEST_P(ServiceWorkerJobTest, RegisterBadOrigin) {}

// A fake instance client for toggling whether a fetch event handler exists.
class FetchHandlerInstanceClient : public FakeEmbeddedWorkerInstanceClient {};

TEST_P(ServiceWorkerJobTest, FetchHandlerType) {}

// Test that clients are alerted of new registrations if they are
// in-scope, so that Clients.claim() or ServiceWorkerContainer.ready work
// correctly.
TEST_P(ServiceWorkerJobTest, AddRegistrationToMatchingerHosts) {}

namespace {  // Helpers for the update job tests.

const char kNoChangeOrigin[] =;
const char kScope[] =;
const char kScript[] =;

const char kHeaders[] =;
const char kBody[] =;
const char kNewBody[] =;

void WriteResponse(
    mojo::Remote<storage::mojom::ServiceWorkerResourceWriter>& writer,
    const std::string& headers,
    mojo_base::BigBuffer body) {}

void WriteStringResponse(
    mojo::Remote<storage::mojom::ServiceWorkerResourceWriter>& writer,
    const std::string& body) {}

class UpdateJobTestHelper : public EmbeddedWorkerTestHelper,
                            public ServiceWorkerRegistration::Listener,
                            public ServiceWorkerContextCoreObserver {};

}  // namespace

// This class is for cases that can be impacted by different update check
// types.
class ServiceWorkerUpdateJobTest : public ServiceWorkerJobTest {};

INSTANTIATE_TEST_SUITE_P();

// Make sure that the same registration is used and the update_via_cache value
// is updated when registering a service worker with the same parameter except
// for updateViaCache.
TEST_P(ServiceWorkerUpdateJobTest, RegisterWithDifferentUpdateViaCache) {}

TEST_P(ServiceWorkerUpdateJobTest, Update_NoChange) {}

TEST_P(ServiceWorkerUpdateJobTest, Update_BumpLastUpdateCheckTime) {}

TEST_P(ServiceWorkerUpdateJobTest, Update_NewVersion) {}

// Test that the update job uses the script URL of the newest worker when the
// job starts, rather than when it is scheduled.
TEST_P(ServiceWorkerUpdateJobTest, Update_ScriptUrlChanged) {}

// Test that update fails if the incumbent worker was evicted
// during the update job (this can happen on disk cache failure).
TEST_P(ServiceWorkerUpdateJobTest, Update_EvictedIncumbent) {}

TEST_P(ServiceWorkerUpdateJobTest, Update_UninstallingRegistration) {}

TEST_P(ServiceWorkerUpdateJobTest, RegisterMultipleTimesWhileUninstalling) {}

// Test that activation doesn't complete if it's triggered by removing a
// controllee and starting the worker failed due to shutdown.
TEST_P(ServiceWorkerUpdateJobTest, ActivateCancelsOnShutdown) {}

// Update job should handle the COEP header appropriately.
TEST_P(ServiceWorkerUpdateJobTest, Update_CrossOriginEmbedderPolicyValue) {}

class WaitForeverInstallWorker : public FakeServiceWorker {};

// Test that the job queue doesn't get stuck by bad workers.
TEST_P(ServiceWorkerJobTest, TimeoutBadJobs) {}

}  // namespace content