chromium/content/browser/service_worker/service_worker_test_utils.h

// 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.

#ifndef CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_TEST_UTILS_H_
#define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_TEST_UTILS_H_

#include <memory>

#include "base/command_line.h"
#include "base/containers/queue.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/memory/weak_ptr.h"
#include "base/run_loop.h"
#include "components/services/storage/public/mojom/service_worker_storage_control.mojom.h"
#include "content/browser/service_worker/service_worker_cache_writer.h"
#include "content/browser/service_worker/service_worker_host.h"
#include "content/browser/service_worker/service_worker_single_script_update_checker.h"
#include "content/common/navigation_client.mojom.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "mojo/public/cpp/bindings/associated_remote.h"
#include "mojo/public/cpp/bindings/pending_associated_receiver.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "net/base/completion_once_callback.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_provider.mojom.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom.h"

namespace blink {
class StorageKey;
}  // namespace blink

namespace content {

class EmbeddedWorkerTestHelper;
class ScopedServiceWorkerClient;
class ServiceWorkerClient;
class ServiceWorkerContainerHost;
class ServiceWorkerContext;
class ServiceWorkerHost;
class ServiceWorkerRegistration;
class ServiceWorkerRegistry;
class ServiceWorkerVersion;

base::OnceCallback<void(blink::ServiceWorkerStatusCode)>
ReceiveServiceWorkerStatus(std::optional<blink::ServiceWorkerStatusCode>* out,
                           base::OnceClosure quit_closure);

blink::ServiceWorkerStatusCode WarmUpServiceWorker(
    ServiceWorkerVersion* version);

bool WarmUpServiceWorker(ServiceWorkerContext& service_worker_context,
                         const GURL& url);

blink::ServiceWorkerStatusCode StartServiceWorker(
    ServiceWorkerVersion* version);

void StopServiceWorker(ServiceWorkerVersion* version);

// A smart pointer of a committed `ServiceWorkerClient`, used for tests
// involving `ServiceWorkerContainerHost`. The underlying `ServiceWorkerClient`
// is kept alive until `this` is destroyed or `host_remote()` is closed.
class CommittedServiceWorkerClient final {};

// Creates an uncommitted service worker client.
// For clients/ServiceWorkerContainerHost that finished navigation, use
// `CommittedServiceWorkerClient`.
ScopedServiceWorkerClient CreateServiceWorkerClient(
    ServiceWorkerContextCore* context,
    const GURL& document_url,
    const url::Origin& top_frame_origin,
    bool are_ancestors_secure = true,
    int frame_tree_node_id = 1);
ScopedServiceWorkerClient CreateServiceWorkerClient(
    ServiceWorkerContextCore* context,
    const GURL& document_url,
    bool are_ancestors_secure = true,
    int frame_tree_node_id = 1);
ScopedServiceWorkerClient CreateServiceWorkerClient(
    ServiceWorkerContextCore* context,
    bool are_ancestors_secure = true,
    int frame_tree_node_id = 1);

std::unique_ptr<ServiceWorkerHost> CreateServiceWorkerHost(
    int process_id,
    bool is_parent_frame_secure,
    ServiceWorkerVersion& hosted_version,
    base::WeakPtr<ServiceWorkerContextCore> context);

// Calls CreateNewRegistration() synchronously.
scoped_refptr<ServiceWorkerRegistration> CreateNewServiceWorkerRegistration(
    ServiceWorkerRegistry* registry,
    const blink::mojom::ServiceWorkerRegistrationOptions& options,
    const blink::StorageKey& key);

// Calls CreateNewVersion() synchronously.
scoped_refptr<ServiceWorkerVersion> CreateNewServiceWorkerVersion(
    ServiceWorkerRegistry* registry,
    scoped_refptr<ServiceWorkerRegistration> registration,
    const GURL& script_url,
    blink::mojom::ScriptType script_type);

// Creates a registration with a waiting version in INSTALLED state.
// |resource_id| is used as ID to represent script resource (|script|) and
// should be unique for each test.
scoped_refptr<ServiceWorkerRegistration>
CreateServiceWorkerRegistrationAndVersion(ServiceWorkerContextCore* context,
                                          const GURL& scope,
                                          const GURL& script,
                                          const blink::StorageKey& key,
                                          int64_t resource_id);

// Writes the script down to |storage| synchronously. This should not be used in
// base::RunLoop since base::RunLoop is used internally to wait for completing
// all of tasks. If it's in another base::RunLoop, consider to use
// WriteToDiskCacheAsync().
storage::mojom::ServiceWorkerResourceRecordPtr WriteToDiskCacheWithIdSync(
    mojo::Remote<storage::mojom::ServiceWorkerStorageControl>& storage,
    const GURL& script_url,
    int64_t resource_id,
    const std::vector<std::pair<std::string, std::string>>& headers,
    const std::string& body,
    const std::string& meta_data);

// Similar to WriteToDiskCacheWithIdSync() but instead of taking a resource id,
// this assigns a new resource ID internally.
storage::mojom::ServiceWorkerResourceRecordPtr WriteToDiskCacheSync(
    mojo::Remote<storage::mojom::ServiceWorkerStorageControl>& storage,
    const GURL& script_url,
    const std::vector<std::pair<std::string, std::string>>& headers,
    const std::string& body,
    const std::string& meta_data);

WriteToDiskCacheCallback;

// Writes the script down to |storage| asynchronously. When completing tasks,
// |callback| will be called. You must wait for |callback| instead of
// base::RunUntilIdle because wiriting to the storage might happen on another
// thread and base::RunLoop could get idle before writes has not finished yet.
void WriteToDiskCacheAsync(
    mojo::Remote<storage::mojom::ServiceWorkerStorageControl>& storage,
    const GURL& script_url,
    const std::vector<std::pair<std::string, std::string>>& headers,
    const std::string& body,
    const std::string& meta_data,
    WriteToDiskCacheCallback callback);

// Calls ServiceWorkerStorageControl::GetNewResourceId() synchronously.
int64_t GetNewResourceIdSync(
    mojo::Remote<storage::mojom::ServiceWorkerStorageControl>& storage);

// A test implementation of ServiceWorkerResourceReader.
//
// This class exposes the ability to expect reads (see ExpectRead*() below).
// Each call to ReadResponseHead() or ReadData() consumes another expected read,
// in the order those reads were expected, so:
//    reader->ExpectReadResponseHeadOk(5);
//    reader->ExpectReadDataOk("abcdef");
//    reader->ExpectReadDataOk("ghijkl");
// Expects these calls, in this order:
//    reader->ReadResponseHead(...);  // reader writes 5 into
//                                    // |response_head->content_length|
//    reader->PrepareReadData();
//    reader->ReadData(...);          // reader writes "abcdef" into |buf|
//    reader->PrepareReadData();
//    reader->ReadData(...);          // reader writes "ghijkl" into |buf|
// If an unexpected call happens, this class DCHECKs.
// An expected read will not complete immediately. It  must be completed by the
// test using CompletePendingRead(). These is a convenience method
// AllExpectedReadsDone() which returns whether there are any expected reads
// that have not yet happened.
class MockServiceWorkerResourceReader
    : public storage::mojom::ServiceWorkerResourceReader {};

// A test implementation of ServiceWorkerResourceWriter.
//
// This class exposes the ability to expect writes (see ExpectWrite*Ok() below).
// Each write to this class via WriteResponseHead() or WriteData() consumes
// another expected write, in the order they were added, so:
//   writer->ExpectWriteResponseHeadOk(5);
//   writer->ExpectWriteDataOk(6);
//   writer->ExpectWriteDataOk(6);
// Expects these calls, in this order:
//   writer->WriteResponseHead(...);  // checks that
//                                    // |response_head->content_length| == 5
//   writer->WriteData(...);  // checks that 6 bytes are being written
//   writer->WriteData(...);  // checks that another 6 bytes are being written
// If this class receives an unexpected call to WriteResponseHead() or
// WriteData(), it DCHECKs.
// Expected writes do not complete synchronously, but rather return without
// running their callback and need to be completed with CompletePendingWrite().
// A convenience method AllExpectedWritesDone() is exposed so tests can ensure
// that all expected writes have been consumed by matching calls to WriteInfo()
// or WriteData().
class MockServiceWorkerResourceWriter
    : public storage::mojom::ServiceWorkerResourceWriter {};

class ServiceWorkerUpdateCheckTestUtils {};

// Reads all data from the given |handle| and returns data as a string.
// This is similar to mojo::BlockingCopyToString() but a bit different. This
// doesn't wait synchronously but keep posting a task when |handle| returns
// MOJO_RESULT_SHOULD_WAIT.
std::string ReadDataPipe(mojo::ScopedDataPipeConsumerHandle handle);

}  // namespace content

#endif  // CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_TEST_UTILS_H_