1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "content/browser/browser_main_loop.h"
6 
7 #include "base/command_line.h"
8 #include "base/system/sys_info.h"
9 #include "base/task/thread_pool/thread_pool_instance.h"
10 #include "base/test/mock_callback.h"
11 #include "base/test/scoped_command_line.h"
12 #include "content/browser/browser_thread_impl.h"
13 #include "content/browser/scheduler/browser_task_executor.h"
14 #include "content/browser/startup_data_impl.h"
15 #include "content/browser/startup_helper.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "content/public/common/content_switches.h"
18 #include "content/public/common/main_function_params.h"
19 #include "content/public/test/test_utils.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21 
22 namespace content {
23 
24 using StrickMockTask =
25     testing::StrictMock<base::MockCallback<base::RepeatingCallback<void()>>>;
26 
27 class BrowserMainLoopTest : public testing::Test {
28  protected:
BrowserMainLoopTest()29   BrowserMainLoopTest() {
30     base::test::ScopedCommandLine scoped_command_line;
31     scoped_command_line.GetProcessCommandLine()->AppendSwitch(
32         switches::kSingleProcess);
33     base::ThreadPoolInstance::Create("Browser");
34     StartBrowserThreadPool();
35     BrowserTaskExecutor::Create();
36   }
37 
~BrowserMainLoopTest()38   ~BrowserMainLoopTest() override {
39     BrowserTaskExecutor::ResetForTesting();
40     for (int id = BrowserThread::UI; id < BrowserThread::ID_COUNT; ++id) {
41       BrowserThreadImpl::ResetGlobalsForTesting(
42           static_cast<BrowserThread::ID>(id));
43     }
44     base::ThreadPoolInstance::Get()->JoinForTesting();
45     base::ThreadPoolInstance::Set(nullptr);
46   }
47 
GetProcessCommandLine()48   const base::CommandLine& GetProcessCommandLine() {
49     return *scoped_command_line_.GetProcessCommandLine();
50   }
51 
52  private:
53   base::test::ScopedCommandLine scoped_command_line_;
54 };  // namespace content
55 
56 // Verify that a single-process browser process has at least as many threads as
57 // the number of cores in its foreground pool.
TEST_F(BrowserMainLoopTest,CreateThreadsInSingleProcess)58 TEST_F(BrowserMainLoopTest, CreateThreadsInSingleProcess) {
59   MainFunctionParams main_function_params(GetProcessCommandLine());
60 
61   StartupDataImpl startup_data;
62   startup_data.io_thread = BrowserTaskExecutor::CreateIOThread();
63   main_function_params.startup_data = &startup_data;
64 
65   BrowserMainLoop browser_main_loop(
66       main_function_params,
67       std::make_unique<base::ThreadPoolInstance::ScopedExecutionFence>());
68   browser_main_loop.MainMessageLoopStart();
69   browser_main_loop.Init();
70   browser_main_loop.CreateThreads();
71   EXPECT_GE(base::ThreadPoolInstance::Get()
72                 ->GetMaxConcurrentNonBlockedTasksWithTraitsDeprecated(
73                     {base::TaskPriority::USER_VISIBLE}),
74             base::SysInfo::NumberOfProcessors() - 1);
75   browser_main_loop.ShutdownThreadsAndCleanUp();
76   BrowserTaskExecutor::ResetForTesting();
77 }
78 
TEST_F(BrowserMainLoopTest,PostTaskToIOThreadBeforeThreadCreationDoesNotRunTask)79 TEST_F(BrowserMainLoopTest,
80        PostTaskToIOThreadBeforeThreadCreationDoesNotRunTask) {
81   MainFunctionParams main_function_params(GetProcessCommandLine());
82 
83   StartupDataImpl startup_data;
84   startup_data.io_thread = BrowserTaskExecutor::CreateIOThread();
85   main_function_params.startup_data = &startup_data;
86 
87   BrowserMainLoop browser_main_loop(
88       main_function_params,
89       std::make_unique<base::ThreadPoolInstance::ScopedExecutionFence>());
90   browser_main_loop.MainMessageLoopStart();
91   browser_main_loop.Init();
92 
93   StrickMockTask task;
94 
95   // No task should run because IO thread has not been initialized yet.
96   GetIOThreadTaskRunner({})->PostTask(FROM_HERE, task.Get());
97   GetIOThreadTaskRunner({})->PostTask(FROM_HERE, task.Get());
98 
99   content::RunAllPendingInMessageLoop(BrowserThread::IO);
100 
101   EXPECT_CALL(task, Run).Times(2);
102   browser_main_loop.CreateThreads();
103   content::RunAllPendingInMessageLoop(BrowserThread::IO);
104 
105   browser_main_loop.ShutdownThreadsAndCleanUp();
106   BrowserTaskExecutor::ResetForTesting();
107 }
108 
109 }  // namespace content
110