[M120 Migration]Fix for crash during chrome exit
[platform/framework/web/chromium-efl.git] / chrome / browser / chrome_multiprofile_startup_browsertest.cc
1 // Copyright 2022 The Chromium Authors
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 <vector>
6
7 #include "base/files/file_path.h"
8 #include "base/memory/raw_ptr.h"
9 #include "base/strings/strcat.h"
10 #include "base/test/bind.h"
11 #include "build/build_config.h"
12 #include "build/chromeos_buildflags.h"
13 #include "chrome/browser/browser_process.h"
14 #include "chrome/browser/chrome_browser_main.h"
15 #include "chrome/browser/chrome_browser_main_extra_parts.h"
16 #include "chrome/browser/profiles/profile_attributes_entry.h"
17 #include "chrome/browser/profiles/profile_attributes_storage.h"
18 #include "chrome/browser/profiles/profile_manager.h"
19 #include "chrome/browser/profiles/profile_test_util.h"
20 #include "chrome/browser/profiles/profile_window.h"
21 #include "chrome/browser/ui/browser.h"
22 #include "chrome/browser/ui/browser_finder.h"
23 #include "chrome/browser/ui/profiles/profile_picker.h"
24 #include "chrome/common/chrome_constants.h"
25 #include "chrome/common/pref_names.h"
26 #include "chrome/test/base/in_process_browser_test.h"
27 #include "components/prefs/pref_service.h"
28 #include "content/public/test/browser_test.h"
29 #include "testing/gmock/include/gmock/gmock.h"
30
31 using ::testing::_;
32 using ::testing::InSequence;
33 using ::testing::Matcher;
34 using ::testing::Mock;
35 using ::testing::Property;
36 using ::testing::ValuesIn;
37
38 #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH)
39 #error Not supported on this platform.
40 #endif
41
42 namespace {
43
44 class MockMainExtraParts : public ChromeBrowserMainExtraParts {
45  public:
46   MOCK_METHOD(void, PreProfileInit, ());
47   MOCK_METHOD(void, PostProfileInit, (Profile*, bool));
48   MOCK_METHOD(void, PreBrowserStart, ());
49   MOCK_METHOD(void, PostBrowserStart, ());
50   MOCK_METHOD(void, PreMainMessageLoopRun, ());
51 };
52
53 const char kOtherProfileDirPath[] = "Other";
54
55 MATCHER_P(BaseNameEquals,
56           basename,
57           base::StrCat({negation ? "doesn't equal " : "equals ", basename})) {
58   return arg == base::FilePath::FromASCII(basename);
59 }
60
61 Matcher<Profile*> HasBaseName(const char* basename) {
62   return Property("basename", &Profile::GetBaseName, BaseNameEquals(basename));
63 }
64
65 struct MultiProfileStartupTestParam {
66   // Whether the profile picker should be shown on startup.
67   const bool should_show_profile_picker;
68
69   struct PostInitExpectedCall {
70     // Matcher for the expected `profile` argument to `PostProfileInit()`
71     const Matcher<Profile*> profile_matcher;
72
73     // Expected value for the `is_initial_profile` argument to
74     // `PostProfileInit()`
75     const bool is_initial_profile;
76   };
77
78   // Call expectations for the `PostProfileInit()` method. The expectations
79   // should themselves be listed in the expected call order.
80   //
81   // The first one is checked in `CreatedBrowserMainParts()` as part of startup,
82   // and the remaining ones in the test body.
83   const std::vector<PostInitExpectedCall> expected_post_profile_init_call_args;
84 };
85
86 const MultiProfileStartupTestParam kTestParams[] = {
87     {.should_show_profile_picker = false,
88      .expected_post_profile_init_call_args =
89          {{HasBaseName(chrome::kInitialProfile), true},
90           {HasBaseName(kOtherProfileDirPath), false}}},
91     {.should_show_profile_picker = true,
92      .expected_post_profile_init_call_args = {
93          {HasBaseName(chrome::kInitialProfile), true},
94          {HasBaseName(kOtherProfileDirPath), false}}}};
95
96 // Creates a new profile to be picked up on the actual test.
97 void SetUpSecondaryProfileForPreTest(
98     const base::FilePath& profile_dir_basename) {
99   ProfileManager* profile_manager = g_browser_process->profile_manager();
100   base::FilePath profile_path =
101       profile_manager->user_data_dir().Append(profile_dir_basename);
102
103   profiles::testing::CreateProfileSync(profile_manager, profile_path);
104
105   // Mark newly created profile as active.
106   ProfileAttributesEntry* entry =
107       profile_manager->GetProfileAttributesStorage()
108           .GetProfileAttributesWithPath(profile_path);
109   ASSERT_NE(entry, nullptr);
110   entry->SetActiveTimeToNow();
111 }
112
113 void CreateBrowserForProfileDir(const base::FilePath& profile_dir_basename) {
114   profiles::testing::SwitchToProfileSync(
115       g_browser_process->profile_manager()->user_data_dir().Append(
116           profile_dir_basename));
117 }
118
119 }  // namespace
120
121 class ChromeMultiProfileStartupBrowserTestBase
122     : public InProcessBrowserTest,
123       public testing::WithParamInterface<MultiProfileStartupTestParam> {
124  public:
125   ChromeMultiProfileStartupBrowserTestBase() {
126     // Avoid providing a URL for the browser to open, allows the profile picker
127     // to be displayed on startup when it is enabled.
128     set_open_about_blank_on_browser_launch(false);
129   }
130
131   void CreatedBrowserMainParts(content::BrowserMainParts* parts) override {
132     InProcessBrowserTest::CreatedBrowserMainParts(parts);
133
134     // Skip expectations preparation for the PRE_ step.
135     if (GetTestPreCount() != 0)
136       return;
137
138     auto mock_part = std::make_unique<MockMainExtraParts>();
139     mock_part_ = mock_part.get();
140     static_cast<ChromeBrowserMainParts*>(parts)->AddParts(std::move(mock_part));
141
142     // At least one entry for the initial call is needed.
143     ASSERT_FALSE(GetParam().expected_post_profile_init_call_args.empty());
144
145     // The basic callbacks should be called only once.
146     EXPECT_CALL(*mock_part_, PreProfileInit()).Times(1);
147     EXPECT_CALL(*mock_part_, PreBrowserStart()).Times(1);
148     EXPECT_CALL(*mock_part_, PostBrowserStart()).Times(1);
149     EXPECT_CALL(*mock_part_, PreMainMessageLoopRun()).Times(1);
150
151     {
152       const auto& call_args = GetParam().expected_post_profile_init_call_args;
153       InSequence s;
154       for (const auto& expected_args : call_args) {
155         EXPECT_CALL(*mock_part_,
156                     PostProfileInit(expected_args.profile_matcher,
157                                     expected_args.is_initial_profile));
158       }
159     }
160   }
161
162   raw_ptr<MockMainExtraParts, AcrossTasksDanglingUntriaged> mock_part_;
163 };
164
165 IN_PROC_BROWSER_TEST_P(ChromeMultiProfileStartupBrowserTestBase,
166                        PRE_PostProfileInitInvocation) {
167   SetUpSecondaryProfileForPreTest(
168       base::FilePath::FromASCII(kOtherProfileDirPath));
169   g_browser_process->local_state()->SetBoolean(
170       prefs::kBrowserShowProfilePickerOnStartup,
171       GetParam().should_show_profile_picker);
172
173   // Need to close the browser window manually so that the real test does not
174   // treat it as session restore.
175   CloseAllBrowsers();
176 }
177
178 // Make sure that the second profile creation causes `PostProfileInit()` to be
179 // called a second time.
180 IN_PROC_BROWSER_TEST_P(ChromeMultiProfileStartupBrowserTestBase,
181                        PostProfileInitInvocation) {
182   EXPECT_EQ(2u, g_browser_process->profile_manager()->GetNumberOfProfiles());
183   if (GetParam().should_show_profile_picker) {
184     EXPECT_EQ(0u, chrome::GetTotalBrowserCount());
185     EXPECT_TRUE(ProfilePicker::IsOpen());
186   } else {
187     EXPECT_EQ(1u, chrome::GetTotalBrowserCount());
188     EXPECT_NE(base::FilePath::FromASCII(kOtherProfileDirPath),
189               browser()->profile()->GetPath().BaseName());
190     EXPECT_FALSE(ProfilePicker::IsOpen());
191   }
192
193   // TODO(https://crbug.com/1288766): In some cases, profile creation is
194   // triggered by restoring the previously opened profile, and the test
195   // expectations in terms of `PostProfileInit()` calls can
196   // be met without opening browsers. We still open them for consistency, at
197   // least until we can make the test behaviour stricter.
198   if (GetParam().should_show_profile_picker) {
199     // No browser was previously open, as verified at the beginning of the test.
200     // So we start by opening the browser for the default profile.
201     CreateBrowserForProfileDir(
202         base::FilePath::FromASCII(chrome::kInitialProfile));
203   }
204   CreateBrowserForProfileDir(base::FilePath::FromASCII(kOtherProfileDirPath));
205
206   EXPECT_EQ(2u, chrome::GetTotalBrowserCount());
207 }
208
209 INSTANTIATE_TEST_SUITE_P(All,
210                          ChromeMultiProfileStartupBrowserTestBase,
211                          ValuesIn(kTestParams));