910e62b5创建于 1月15日历史提交
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <optional>
#include <string>
#include <utility>
#include <variant>

#include "base/command_line.h"
#include "base/feature_list.h"
#include "base/task/thread_pool/thread_pool_instance.h"
#include "build/build_config.h"
#include "content/public/app/content_main_delegate.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/common/content_client.h"
#include "content/public/common/main_function_params.h"
#include "content/public/gpu/content_gpu_client.h"
#include "content/public/renderer/content_renderer_client.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_shell_main_delegate.h"
#include "content/public/utility/content_utility_client.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/abseil-cpp/absl/functional/overload.h"

namespace variations {
class VariationsIdsProvider;
}

namespace content {

namespace {

using ::testing::_;
using ::testing::AtMost;
using ::testing::DoAll;
using ::testing::Invoke;
using ::testing::Return;
using InvokedIn = ContentMainDelegate::InvokedIn;
using VariationsIdsProvider = variations::VariationsIdsProvider;

// Mocks only the cross-platform methods of ContentMainDelegate. Also calls the
// parent implementation of each method, since the test setup may depend on it.
class MockContentMainDelegate : public ContentBrowserTestShellMainDelegate {
 public:
  using Super = ContentBrowserTestShellMainDelegate;

  MOCK_METHOD(std::optional<int>, MockBasicStartupComplete, ());
  std::optional<int> BasicStartupComplete() override {
    std::optional<int> result = MockBasicStartupComplete();
    // Check for early exit code.
    if (result.has_value())
      return result;
    return Super::BasicStartupComplete();
  }

  MOCK_METHOD(void, MockPreSandboxStartup, ());
  void PreSandboxStartup() override {
    MockPreSandboxStartup();
    Super::PreSandboxStartup();
  }

  MOCK_METHOD(void, MockSandboxInitialized, (const std::string&));
  void SandboxInitialized(const std::string& process_type) override {
    MockSandboxInitialized(process_type);
    Super::SandboxInitialized(process_type);
  }

  // The return value of RunProcess is platform-dependent and the startup
  // sequence depends heavily on it, so don't allow it to be mocked.
  MOCK_METHOD(void, MockRunProcess, (const std::string&, MainFunctionParams));
  std::variant<int, MainFunctionParams> RunProcess(
      const std::string& process_type,
      MainFunctionParams main_function_params) override {
    // MainFunctionParams is move-only so pass a dummy to the mock.
    MainFunctionParams dummy_main_function_params(
        base::CommandLine::ForCurrentProcess());
    MockRunProcess(process_type, std::move(dummy_main_function_params));
    return Super::RunProcess(process_type, std::move(main_function_params));
  }

  MOCK_METHOD(void, MockProcessExiting, (const std::string&));
  void ProcessExiting(const std::string& process_type) override {
    MockProcessExiting(process_type);
    Super::ProcessExiting(process_type);
  }

  // The return value of ShouldLockSchemeRegistry is dangerous to override so
  // don't allow it to be mocked.
  MOCK_METHOD(void, MockShouldLockSchemeRegistry, ());
  bool ShouldLockSchemeRegistry() override {
    MockShouldLockSchemeRegistry();
    return Super::ShouldLockSchemeRegistry();
  }

  MOCK_METHOD(std::optional<int>, MockPreBrowserMain, ());
  std::optional<int> PreBrowserMain() override {
    std::optional<int> result = MockPreBrowserMain();
    // Check for early exit code.
    if (result.has_value())
      return result;
    return Super::PreBrowserMain();
  }

  // No need to call the parent delegate for these methods since they have no
  // side effects.
  MOCK_METHOD(bool, ShouldCreateFeatureList, (InvokedIn), (override));
  MOCK_METHOD(bool, ShouldInitializeMojo, (InvokedIn), (override));

  MOCK_METHOD(VariationsIdsProvider*, MockCreateVariationsIdsProvider, ());
  VariationsIdsProvider* CreateVariationsIdsProvider() override {
    VariationsIdsProvider* result = MockCreateVariationsIdsProvider();
    if (result)
      return result;
    return Super::CreateVariationsIdsProvider();
  }

  MOCK_METHOD(std::optional<int>, MockPostEarlyInitialization, (InvokedIn));
  std::optional<int> PostEarlyInitialization(InvokedIn invoked_in) override {
    std::optional<int> result = MockPostEarlyInitialization(invoked_in);
    // Check for early exit code.
    if (result.has_value())
      return result;
    return Super::PostEarlyInitialization(invoked_in);
  }

  MOCK_METHOD(ContentClient*, MockCreateContentClient, ());
  ContentClient* CreateContentClient() override {
    ContentClient* result = MockCreateContentClient();
    if (result)
      return result;
    return Super::CreateContentClient();
  }

  MOCK_METHOD(ContentBrowserClient*, MockCreateContentBrowserClient, ());
  ContentBrowserClient* CreateContentBrowserClient() override {
    ContentBrowserClient* result = MockCreateContentBrowserClient();
    if (result)
      return result;
    return Super::CreateContentBrowserClient();
  }

  MOCK_METHOD(ContentGpuClient*, MockCreateContentGpuClient, ());
  ContentGpuClient* CreateContentGpuClient() override {
    ContentGpuClient* result = MockCreateContentGpuClient();
    if (result)
      return result;
    return Super::CreateContentGpuClient();
  }

  MOCK_METHOD(ContentRendererClient*, MockCreateContentRendererClient, ());
  ContentRendererClient* CreateContentRendererClient() override {
    ContentRendererClient* result = MockCreateContentRendererClient();
    if (result)
      return result;
    return Super::CreateContentRendererClient();
  }

  MOCK_METHOD(ContentUtilityClient*, MockCreateContentUtilityClient, ());
  ContentUtilityClient* CreateContentUtilityClient() override {
    ContentUtilityClient* result = MockCreateContentUtilityClient();
    if (result)
      return result;
    return Super::CreateContentUtilityClient();
  }
};

MATCHER_P(InvokedInMatcher, process_type, "") {
  // `arg` is an std::variant. Return true if the type held by the variant is
  // correct for `process_type` (empty means the browser process).
  return std::visit(absl::Overload{
                        [&](ContentMainDelegate::InvokedInBrowserProcess) {
                          return process_type.empty();
                        },
                        [&](ContentMainDelegate::InvokedInChildProcess) {
                          return !process_type.empty();
                        },
                    },
                    arg);
}

// Tests that methods of ContentMainDelegate are called in the expected order.
class ContentMainRunnerImplBrowserTest : public ContentBrowserTest {
 protected:
  using Self = ContentMainRunnerImplBrowserTest;
  using Super = ContentBrowserTest;

  void SetUp() override {
    // Empty process name means the browser process.
    const std::string kBrowserProcessType = "";

    // These methods may or may not be called, depending on configuration.
    EXPECT_CALL(mock_delegate_, MockShouldLockSchemeRegistry())
        .Times(AtMost(1));
    EXPECT_CALL(mock_delegate_, MockCreateVariationsIdsProvider())
        .Times(AtMost(1));
    // CreateContentClient() is only called if GetContentClient() returns null.
    EXPECT_CALL(mock_delegate_, MockCreateContentClient()).Times(AtMost(1));

    // ContentBrowserTestShellMainDelegate calls these internally, so allow
    // extra calls to them out of sequence.
    EXPECT_CALL(mock_delegate_, ShouldCreateFeatureList(_))
        .WillRepeatedly(Return(true));
    EXPECT_CALL(mock_delegate_, ShouldInitializeMojo(_))
        .WillRepeatedly(Return(true));

    // Expect the following entry points to be called, in order.
    //
    // BrowserTestBase::SetUp() calls ContentMain(), which instantiates a
    // ContentMainRunnerImpl, which calls the entry points in
    // ContentMainDelegate. So test expectations must be installed before
    // calling the inherited SetUp().
    ::testing::InSequence s;
    EXPECT_CALL(mock_delegate_, MockBasicStartupComplete())
        .WillOnce(DoAll(
            // Test the starting state of ContentMainRunnerImpl.
            Invoke(this, &Self::TestBasicStartupComplete),
            Return(std::nullopt)));
    EXPECT_CALL(mock_delegate_, MockCreateContentBrowserClient());
    EXPECT_CALL(mock_delegate_, MockPreSandboxStartup());
    EXPECT_CALL(mock_delegate_, MockSandboxInitialized(kBrowserProcessType));
    EXPECT_CALL(mock_delegate_,
                ShouldCreateFeatureList(InvokedInMatcher(kBrowserProcessType)))
        .WillOnce(Return(true));
    EXPECT_CALL(mock_delegate_,
                ShouldInitializeMojo(InvokedInMatcher(kBrowserProcessType)))
        .WillOnce(Return(true));
    EXPECT_CALL(mock_delegate_, MockPreBrowserMain())
        .WillOnce(Return(std::nullopt));
    EXPECT_CALL(mock_delegate_, MockPostEarlyInitialization(
                                    InvokedInMatcher(kBrowserProcessType)))
        .WillOnce(DoAll(Invoke(this, &Self::TestPostEarlyInitialization),
                        Return(std::nullopt)));
    EXPECT_CALL(mock_delegate_, MockRunProcess(kBrowserProcessType, _));
#if !BUILDFLAG(IS_ANDROID)
    // Android never calls ProcessExiting, since it leaks its ContentMainRunner
    // and ProcessExiting is called from the destructor.
    EXPECT_CALL(mock_delegate_, MockProcessExiting(kBrowserProcessType));
#endif

    // This will call ContentMain(), which should satisfy the expectations
    // above.
    Super::SetUp();
  }

  ContentMainDelegate* GetOptionalContentMainDelegateOverride() override {
    return &mock_delegate_;
  }

  void TestBasicStartupComplete() {
    // The PostEarlyInitialization test checks that ContentMainRunnerImpl set up
    // the FeatureList. This test is invalid if it already exists
    // before starting.
    EXPECT_FALSE(base::FeatureList::GetInstance());
  }

  void TestPostEarlyInitialization() {
    // ContentMainRunnerImpl should have set up the ThreadPoolInstance and
    // FeatureList by this point.
    EXPECT_TRUE(base::ThreadPoolInstance::Get());
    EXPECT_TRUE(base::FeatureList::GetInstance());
  }

  ::testing::StrictMock<MockContentMainDelegate> mock_delegate_;
};

IN_PROC_BROWSER_TEST_F(ContentMainRunnerImplBrowserTest, StartupSequence) {
  // All of the work is done in SetUp().
}

}  // namespace

}  // namespace content