1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192
  193
  194
  195
  196
  197
  198
  199
  200
  201
  202
  203
  204
  205
  206
  207
  208
  209
  210
  211
  212
  213
  214
  215
  216
  217
  218
  219
  220
  221
  222
  223
  224
  225
  226
  227
  228
  229
  230
  231
  232
  233
  234
  235
  236
  237
  238
  239
  240
  241
  242
  243
  244

content / public / test / content_browser_test.cc [blame]

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

#include "content/public/test/content_browser_test.h"

#include "base/check.h"
#include "base/check_op.h"
#include "base/command_line.h"
#include "base/files/file.h"
#include "base/files/file_util.h"
#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/task/current_thread.h"
#include "build/build_config.h"
#include "build/chromecast_buildflags.h"
#include "build/chromeos_buildflags.h"
#include "content/browser/renderer_host/render_frame_host_impl.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/common/content_paths.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/url_constants.h"
#include "content/public/test/content_browser_test_content_browser_client.h"
#include "content/public/test/test_browser_context.h"
#include "content/shell/browser/shell.h"
#include "content/shell/browser/shell_browser_context.h"
#include "content/shell/browser/shell_paths.h"
#include "content/shell/common/shell_switches.h"
#include "content/test/test_content_client.h"
#include "ui/events/platform/platform_event_source.h"

#if BUILDFLAG(IS_MAC)
#include "base/apple/foundation_util.h"
#include "content/shell/app/paths_mac.h"
#endif

// TODO(crbug.com/40118868): Revisit the macro expression once build flag switch
// of lacros-chrome is complete.
#if BUILDFLAG(IS_CHROMEOS_LACROS) || BUILDFLAG(IS_LINUX)
#include "ui/base/ime/init/input_method_initializer.h"
#endif

#if BUILDFLAG(IS_CHROMEOS)
#include "content/public/test/network_connection_change_simulator.h"
#endif

#if defined(USE_AURA) && defined(TOOLKIT_VIEWS)
#include "ui/views/test/widget_test_api.h"  // nogncheck
#endif

namespace content {

ContentBrowserTest::ContentBrowserTest() {
  // In content browser tests ContentBrowserTestContentBrowserClient must be
  // used. ContentBrowserTestContentBrowserClient's constructor (and destructor)
  // uses this same function to change the ContentBrowserClient.
  ContentClient::SetCanChangeContentBrowserClientForTesting(false);
#if BUILDFLAG(IS_MAC)
  base::apple::SetOverrideAmIBundled(true);

  // See comment in InProcessBrowserTest::InProcessBrowserTest().
  base::FilePath content_shell_path;
  CHECK(base::PathService::Get(base::FILE_EXE, &content_shell_path));
  content_shell_path = content_shell_path.DirName();
  content_shell_path = content_shell_path.Append(
      FILE_PATH_LITERAL("Content Shell.app/Contents/MacOS/Content Shell"));
  CHECK(base::CreateDirectory(content_shell_path.DirName()));
  if (base::File file(content_shell_path,
                      base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_WRITE);
      !file.IsValid()) {
    // Diagnostics for https://crbug.com/345765743.
    const auto last_errno = errno;
    CHECK(base::PathExists(content_shell_path))
        << "Failed to create \"" << content_shell_path
        << "\": " << base::File::ErrorToString(file.error_details())
        << "; errno = " << last_errno;
  }
  file_exe_override_.emplace(base::FILE_EXE, content_shell_path,
                             /*is_absolute=*/false, /*create=*/false);
#endif

  // The HTTPS test server must be setup here as different browser test suites
  // have different bundle behavior on macOS, and the HTTPS test server
  // constructor reads in the local test root cert. It might be possible
  // to move this to BrowserTestBase in the future.
  embedded_https_test_server_ = std::make_unique<net::EmbeddedTestServer>(
      net::EmbeddedTestServer::TYPE_HTTPS);
  // Default hostnames for the HTTPS test server. Test fixtures can call this
  // with different hostnames (before starting the server) to override.
  embedded_https_test_server_->SetCertHostnames(
      {"example.com", "*.example.com", "foo.com", "*.foo.com", "bar.com",
       "*.bar.com", "a.com", "*.a.com", "b.com", "*.b.com", "c.com",
       "*.c.com"});

  embedded_test_server()->AddDefaultHandlers(GetTestDataFilePath());
  embedded_https_test_server().AddDefaultHandlers(GetTestDataFilePath());
}

ContentBrowserTest::~ContentBrowserTest() {
}

void ContentBrowserTest::SetUp() {
  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
  SetUpCommandLine(command_line);

#if BUILDFLAG(IS_MAC)
  // See InProcessBrowserTest::PrepareTestCommandLine().
  base::FilePath subprocess_path;
  base::PathService::Get(base::FILE_EXE, &subprocess_path);
  subprocess_path = subprocess_path.DirName().DirName();
  DCHECK_EQ(subprocess_path.BaseName().value(), "Contents");
  subprocess_path = subprocess_path.Append(
      "Frameworks/Content Shell Framework.framework/Helpers/Content Shell "
      "Helper.app/Contents/MacOS/Content Shell Helper");
  command_line->AppendSwitchPath(switches::kBrowserSubprocessPath,
                                 subprocess_path);

  // Needs to happen before ContentMain().
  OverrideFrameworkBundlePath();
  OverrideOuterBundlePath();
  OverrideChildProcessPath();
  OverrideSourceRootPath();
  OverrideBundleID();
#endif

#if defined(USE_AURA) && defined(TOOLKIT_VIEWS) && !BUILDFLAG(IS_CASTOS)
  // https://crbug.com/695054: Ignore window activation/deactivation to make
  // the Chrome-internal focus unaffected by OS events caused by running tests
  // in parallel.
  views::DisableActivationChangeHandlingForTests();
#endif

  // LinuxInputMethodContextFactory has to be initialized.
// TODO(crbug.com/40118868): Revisit the macro expression once build flag switch
// of lacros-chrome is complete.
#if BUILDFLAG(IS_CHROMEOS_LACROS) || BUILDFLAG(IS_LINUX)
  ui::InitializeInputMethodForTesting();
#endif

  ui::PlatformEventSource::SetIgnoreNativePlatformEvents(true);

// Enable this switch to prevent undesired viewport resizing for the scaling
// issue addressed in https://crrev.com/c/4615623.
#if BUILDFLAG(IS_IOS)
  command_line->AppendSwitch(switches::kPreventResizingContentsForTesting);
#endif

  BrowserTestBase::SetUp();
}

void ContentBrowserTest::TearDown() {
  BrowserTestBase::TearDown();

  if (embedded_https_test_server().Started()) {
    ASSERT_TRUE(embedded_https_test_server().ShutdownAndWaitUntilComplete());
  }

  // LinuxInputMethodContextFactory has to be shutdown.
// TODO(crbug.com/40118868): Revisit the macro expression once build flag switch
// of lacros-chrome is complete.
#if BUILDFLAG(IS_CHROMEOS_LACROS) || BUILDFLAG(IS_LINUX)
  ui::ShutdownInputMethodForTesting();
#endif
}

void ContentBrowserTest::PreRunTestOnMainThread() {
#if BUILDFLAG(IS_CHROMEOS)
  NetworkConnectionChangeSimulator network_change_simulator;
  network_change_simulator.InitializeChromeosConnectionType();
#endif

  CHECK_EQ(Shell::windows().size(), 1u);
  shell_ = Shell::windows()[0];
  SetInitialWebContents(shell_->web_contents());

#if BUILDFLAG(IS_MAC)
  // On Mac, without the following autorelease pool, code which is directly
  // executed (as opposed to executed inside a message loop) would autorelease
  // objects into a higher-level pool. This pool is not recycled in-sync with
  // the message loops' pools and causes problems with code relying on
  // deallocation via an autorelease pool (such as browser window closure and
  // browser shutdown). To avoid this, the following pool is recycled after each
  // time code is directly executed.
  pool_.emplace();
#endif

  // Pump startup related events.
  DCHECK(base::CurrentUIThread::IsSet());
  base::RunLoop().RunUntilIdle();

#if BUILDFLAG(IS_MAC)
  pool_->Recycle();
#endif

  pre_run_test_executed_ = true;
}

void ContentBrowserTest::PostRunTestOnMainThread() {
  // This code is failing when the test is overriding PreRunTestOnMainThread()
  // without the required call to ContentBrowserTest::PreRunTestOnMainThread().
  // This is a common error causing a crash on MAC.
  DCHECK(pre_run_test_executed_);

#if BUILDFLAG(IS_MAC)
  pool_.reset();
#endif

  for (RenderProcessHost::iterator i(RenderProcessHost::AllHostsIterator());
       !i.IsAtEnd(); i.Advance()) {
    i.GetCurrentValue()->FastShutdownIfPossible();
  }

  Shell::Shutdown();
}

Shell* ContentBrowserTest::CreateBrowser() {
  return Shell::CreateNewWindow(
      ShellContentBrowserClient::Get()->browser_context(),
      GURL(url::kAboutBlankURL), nullptr, gfx::Size());
}

Shell* ContentBrowserTest::CreateOffTheRecordBrowser() {
  return Shell::CreateNewWindow(
      ShellContentBrowserClient::Get()->off_the_record_browser_context(),
      GURL(url::kAboutBlankURL), nullptr, gfx::Size());
}

std::unique_ptr<TestBrowserContext>
ContentBrowserTest::CreateTestBrowserContext() {
  base::FilePath user_data_path;
  EXPECT_TRUE(base::PathService::Get(SHELL_DIR_USER_DATA, &user_data_path));
  base::FilePath browser_context_dir_path;
  EXPECT_TRUE(base::CreateTemporaryDirInDir(
      /*base_dir=*/user_data_path,
      /*prefix=*/FILE_PATH_LITERAL("test_browser_context_"),
      /*new_dir=*/&browser_context_dir_path));
  return std::make_unique<TestBrowserContext>(browser_context_dir_path);
}

base::FilePath ContentBrowserTest::GetTestDataFilePath() {
  return base::FilePath(FILE_PATH_LITERAL("content/test/data"));
}

}  // namespace content