1 // Copyright 2020 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 <memory>
6
7 #include "base/bind.h"
8 #include "base/run_loop.h"
9 #include "base/test/metrics/histogram_tester.h"
10 #include "base/test/scoped_feature_list.h"
11 #include "chrome/browser/browser_features.h"
12 #include "chrome/browser/command_updater_impl.h"
13 #include "chrome/browser/promo_browser_command/promo_browser_command.mojom.h"
14 #include "chrome/browser/ui/chrome_pages.h"
15 #include "chrome/browser/ui/webui/new_tab_page/promo_browser_command/promo_browser_command_handler.h"
16 #include "chrome/common/webui_url_constants.h"
17 #include "chrome/test/base/testing_profile.h"
18 #include "components/content_settings/core/common/pref_names.h"
19 #include "components/password_manager/core/common/password_manager_pref_names.h"
20 #include "components/safe_browsing/core/common/safe_browsing_prefs.h"
21 #include "components/sync_preferences/testing_pref_service_syncable.h"
22 #include "content/public/test/browser_task_environment.h"
23 #include "testing/gmock/include/gmock/gmock.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25 #include "ui/base/window_open_disposition.h"
26
27 using promo_browser_command::mojom::ClickInfo;
28 using promo_browser_command::mojom::ClickInfoPtr;
29 using promo_browser_command::mojom::Command;
30 using promo_browser_command::mojom::CommandHandler;
31
32 namespace {
33
34 class TestCommandHandler : public PromoBrowserCommandHandler {
35 public:
TestCommandHandler(Profile * profile)36 explicit TestCommandHandler(Profile* profile)
37 : PromoBrowserCommandHandler(mojo::PendingReceiver<CommandHandler>(),
38 profile) {}
39 ~TestCommandHandler() override = default;
40
NavigateToURL(const GURL &,WindowOpenDisposition)41 void NavigateToURL(const GURL&, WindowOpenDisposition) override {
42 // The functionality of opening a URL is removed, as it cannot be executed
43 // in a unittest.
44 }
45
GetCommandUpdater()46 CommandUpdater* GetCommandUpdater() override {
47 if (command_updater_)
48 return command_updater_.get();
49 return PromoBrowserCommandHandler::GetCommandUpdater();
50 }
51
SetCommandUpdater(std::unique_ptr<CommandUpdater> command_updater)52 void SetCommandUpdater(std::unique_ptr<CommandUpdater> command_updater) {
53 command_updater_ = std::move(command_updater);
54 // Ensure that all commands are also updated in the new |command_updater|.
55 EnableCommands();
56 }
57
58 std::unique_ptr<CommandUpdater> command_updater_;
59 };
60
61 class MockCommandHandler : public TestCommandHandler {
62 public:
MockCommandHandler(Profile * profile)63 explicit MockCommandHandler(Profile* profile) : TestCommandHandler(profile) {}
64 ~MockCommandHandler() override = default;
65
66 MOCK_METHOD2(NavigateToURL, void(const GURL&, WindowOpenDisposition));
67 };
68
69 class MockCommandUpdater : public CommandUpdaterImpl {
70 public:
MockCommandUpdater(CommandUpdaterDelegate * delegate)71 explicit MockCommandUpdater(CommandUpdaterDelegate* delegate)
72 : CommandUpdaterImpl(delegate) {}
73 ~MockCommandUpdater() override = default;
74
75 MOCK_CONST_METHOD1(IsCommandEnabled, bool(int id));
76 MOCK_CONST_METHOD1(SupportsCommand, bool(int id));
77 };
78
79 // Callback used for testing
80 // PromoBrowserCommandHandler::CanShowPromoWithCommand().
CanShowPromoWithCommandCallback(base::OnceClosure quit_closure,bool * expected_can_show,bool can_show)81 void CanShowPromoWithCommandCallback(base::OnceClosure quit_closure,
82 bool* expected_can_show,
83 bool can_show) {
84 *expected_can_show = can_show;
85 std::move(quit_closure).Run();
86 }
87
88 // Callback used for testing PromoBrowserCommandHandler::ExecuteCommand().
ExecuteCommandCallback(base::OnceClosure quit_closure,bool * expected_command_executed,bool command_executed)89 void ExecuteCommandCallback(base::OnceClosure quit_closure,
90 bool* expected_command_executed,
91 bool command_executed) {
92 *expected_command_executed = command_executed;
93 std::move(quit_closure).Run();
94 }
95
96 // A shorthand for conversion between ClickInfo and WindowOpenDisposition.
DispositionFromClick(const ClickInfo & info)97 WindowOpenDisposition DispositionFromClick(const ClickInfo& info) {
98 return ui::DispositionFromClick(info.middle_button, info.alt_key,
99 info.ctrl_key, info.meta_key, info.shift_key);
100 }
101
102 } // namespace
103
104 class PromoBrowserCommandHandlerTest : public testing::Test {
105 public:
106 PromoBrowserCommandHandlerTest() = default;
107 ~PromoBrowserCommandHandlerTest() override = default;
108
SetUp()109 void SetUp() override {
110 command_handler_ = std::make_unique<MockCommandHandler>(&profile_);
111 }
112
TearDown()113 void TearDown() override { testing::Test::TearDown(); }
114
mock_command_updater()115 MockCommandUpdater* mock_command_updater() {
116 return static_cast<MockCommandUpdater*>(
117 command_handler_->GetCommandUpdater());
118 }
119
CanShowPromoWithCommand(Command command_id)120 bool CanShowPromoWithCommand(Command command_id) {
121 base::RunLoop run_loop;
122 bool can_show = false;
123 command_handler_->CanShowPromoWithCommand(
124 command_id, base::BindOnce(&CanShowPromoWithCommandCallback,
125 run_loop.QuitClosure(), &can_show));
126 run_loop.Run();
127 return can_show;
128 }
129
ExecuteCommand(Command command_id,ClickInfoPtr click_info)130 bool ExecuteCommand(Command command_id, ClickInfoPtr click_info) {
131 base::RunLoop run_loop;
132 bool command_executed = false;
133 command_handler_->ExecuteCommand(
134 command_id, std::move(click_info),
135 base::BindOnce(&ExecuteCommandCallback, run_loop.QuitClosure(),
136 &command_executed));
137 run_loop.Run();
138 return command_executed;
139 }
140
141 protected:
142 content::BrowserTaskEnvironment task_environment_;
143 TestingProfile profile_;
144 std::unique_ptr<MockCommandHandler> command_handler_;
145 };
146
TEST_F(PromoBrowserCommandHandlerTest,SupportedCommands)147 TEST_F(PromoBrowserCommandHandlerTest, SupportedCommands) {
148 base::HistogramTester histogram_tester;
149
150 // Mock out the command updater to test enabling and disabling commands.
151 command_handler_->SetCommandUpdater(
152 std::make_unique<MockCommandUpdater>(command_handler_.get()));
153
154 // Unsupported commands do not get executed and no histogram is logged.
155 EXPECT_CALL(*mock_command_updater(),
156 SupportsCommand(static_cast<int>(Command::kUnknownCommand)))
157 .WillOnce(testing::Return(false));
158
159 EXPECT_FALSE(ExecuteCommand(Command::kUnknownCommand, ClickInfo::New()));
160 histogram_tester.ExpectTotalCount(
161 PromoBrowserCommandHandler::kPromoBrowserCommandHistogramName, 0);
162
163 // Disabled commands do not get executed and no histogram is logged.
164 EXPECT_CALL(*mock_command_updater(),
165 SupportsCommand(static_cast<int>(Command::kUnknownCommand)))
166 .WillOnce(testing::Return(true));
167 EXPECT_CALL(*mock_command_updater(),
168 IsCommandEnabled(static_cast<int>(Command::kUnknownCommand)))
169 .WillOnce(testing::Return(false));
170
171 EXPECT_FALSE(ExecuteCommand(Command::kUnknownCommand, ClickInfo::New()));
172 histogram_tester.ExpectTotalCount(
173 PromoBrowserCommandHandler::kPromoBrowserCommandHistogramName, 0);
174
175 // Only supported and enabled commands get executed for which a histogram is
176 // logged.
177 EXPECT_CALL(*mock_command_updater(),
178 SupportsCommand(static_cast<int>(Command::kUnknownCommand)))
179 .WillOnce(testing::Return(true));
180 EXPECT_CALL(*mock_command_updater(),
181 IsCommandEnabled(static_cast<int>(Command::kUnknownCommand)))
182 .WillOnce(testing::Return(true));
183
184 EXPECT_TRUE(ExecuteCommand(Command::kUnknownCommand, ClickInfo::New()));
185 histogram_tester.ExpectBucketCount(
186 PromoBrowserCommandHandler::kPromoBrowserCommandHistogramName, 0, 1);
187 }
188
TEST_F(PromoBrowserCommandHandlerTest,DisableHandlingCommands)189 TEST_F(PromoBrowserCommandHandlerTest, DisableHandlingCommands) {
190 base::HistogramTester histogram_tester;
191
192 // Disabling features::kPromoBrowserCommands prevents the commands from being
193 // executed.
194 base::test::ScopedFeatureList feature_list;
195 feature_list.InitAndDisableFeature(features::kPromoBrowserCommands);
196
197 // The PromoBrowserCommandHandler instance needs to be recreated for the
198 // feature to take effect.
199 command_handler_ = std::make_unique<MockCommandHandler>(&profile_);
200
201 EXPECT_FALSE(ExecuteCommand(Command::kUnknownCommand, ClickInfo::New()));
202 histogram_tester.ExpectTotalCount(
203 PromoBrowserCommandHandler::kPromoBrowserCommandHistogramName, 0);
204 }
205
TEST_F(PromoBrowserCommandHandlerTest,CanShowPromoWithCommand_OpenSafetyCheck)206 TEST_F(PromoBrowserCommandHandlerTest,
207 CanShowPromoWithCommand_OpenSafetyCheck) {
208 // By default, showing the Safety Check promo is allowed.
209 EXPECT_TRUE(CanShowPromoWithCommand(
210 Command::kOpenSafeBrowsingEnhancedProtectionSettings));
211
212 // In enterprise environments, i.e. if any browser policy is applied, showing
213 // the Safety Check promo is not allowed.
214 TestingProfile::Builder builder;
215 std::unique_ptr<TestingProfile> profile = builder.Build();
216 profile->GetTestingPrefService()->SetManagedPref(
217 prefs::kSafeBrowsingEnabled, std::make_unique<base::Value>(true));
218 EXPECT_FALSE(CanShowPromoWithCommand(Command::kOpenSafetyCheck));
219
220 profile->GetTestingPrefService()->RemoveManagedPref(
221 prefs::kSafeBrowsingEnabled);
222 profile->GetTestingPrefService()->SetManagedPref(
223 password_manager::prefs::kCredentialsEnableService,
224 std::make_unique<base::Value>(true));
225 EXPECT_FALSE(CanShowPromoWithCommand(Command::kOpenSafetyCheck));
226
227 // That's true even if the policy in question is not related to the entries
228 // shown in the Safety Check.
229 profile->GetTestingPrefService()->RemoveManagedPref(
230 password_manager::prefs::kCredentialsEnableService);
231 profile->GetTestingPrefService()->SetManagedPref(
232 prefs::kManagedCookiesAllowedForUrls,
233 std::make_unique<base::Value>(true));
234 EXPECT_FALSE(CanShowPromoWithCommand(Command::kOpenSafetyCheck));
235
236 // Once policies are removed, the command works again.
237 profile->GetTestingPrefService()->RemoveManagedPref(
238 prefs::kManagedCookiesAllowedForUrls);
239 EXPECT_TRUE(CanShowPromoWithCommand(
240 Command::kOpenSafeBrowsingEnhancedProtectionSettings));
241 }
242
TEST_F(PromoBrowserCommandHandlerTest,OpenSafetyCheckCommand)243 TEST_F(PromoBrowserCommandHandlerTest, OpenSafetyCheckCommand) {
244 // The OpenSafetyCheck command opens a new settings window with the Safety
245 // Check, and the correct disposition.
246 ClickInfoPtr info = ClickInfo::New();
247 info->middle_button = true;
248 info->meta_key = true;
249 EXPECT_CALL(
250 *command_handler_,
251 NavigateToURL(GURL(chrome::GetSettingsUrl(chrome::kSafetyCheckSubPage)),
252 DispositionFromClick(*info)));
253 EXPECT_TRUE(ExecuteCommand(Command::kOpenSafetyCheck, std::move(info)));
254 }
255
TEST_F(PromoBrowserCommandHandlerTest,CanShowSafeBrowsingEnhancedProtectionCommandPromo_NoPolicies)256 TEST_F(PromoBrowserCommandHandlerTest,
257 CanShowSafeBrowsingEnhancedProtectionCommandPromo_NoPolicies) {
258 EXPECT_TRUE(CanShowPromoWithCommand(
259 Command::kOpenSafeBrowsingEnhancedProtectionSettings));
260 }
261
TEST_F(PromoBrowserCommandHandlerTest,CanShowSafeBrowsingEnhancedProtectionCommandPromo_EnhancedProtectionEnabled)262 TEST_F(
263 PromoBrowserCommandHandlerTest,
264 CanShowSafeBrowsingEnhancedProtectionCommandPromo_EnhancedProtectionEnabled) {
265 TestingProfile::Builder builder;
266 std::unique_ptr<TestingProfile> profile = builder.Build();
267 profile->GetTestingPrefService()->SetUserPref(
268 prefs::kSafeBrowsingEnhanced, std::make_unique<base::Value>(true));
269 command_handler_ = std::make_unique<MockCommandHandler>(profile.get());
270
271 EXPECT_FALSE(CanShowPromoWithCommand(
272 Command::kOpenSafeBrowsingEnhancedProtectionSettings));
273 }
274
TEST_F(PromoBrowserCommandHandlerTest,CanShowSafeBrowsingEnhancedProtectionCommandPromo_HasSafeBrowsingManaged_NoProtection)275 TEST_F(
276 PromoBrowserCommandHandlerTest,
277 CanShowSafeBrowsingEnhancedProtectionCommandPromo_HasSafeBrowsingManaged_NoProtection) {
278 TestingProfile::Builder builder;
279 std::unique_ptr<TestingProfile> profile = builder.Build();
280 profile->GetTestingPrefService()->SetManagedPref(
281 prefs::kSafeBrowsingEnabled, std::make_unique<base::Value>(false));
282 profile->GetTestingPrefService()->SetManagedPref(
283 prefs::kSafeBrowsingEnhanced, std::make_unique<base::Value>(false));
284 command_handler_ = std::make_unique<MockCommandHandler>(profile.get());
285
286 EXPECT_FALSE(CanShowPromoWithCommand(
287 Command::kOpenSafeBrowsingEnhancedProtectionSettings));
288 }
289
TEST_F(PromoBrowserCommandHandlerTest,CanShowSafeBrowsingEnhancedProtectionCommandPromo_HasSafeBrowsingManaged_StandardProtection)290 TEST_F(
291 PromoBrowserCommandHandlerTest,
292 CanShowSafeBrowsingEnhancedProtectionCommandPromo_HasSafeBrowsingManaged_StandardProtection) {
293 TestingProfile::Builder builder;
294 std::unique_ptr<TestingProfile> profile = builder.Build();
295 profile->GetTestingPrefService()->SetManagedPref(
296 prefs::kSafeBrowsingEnabled, std::make_unique<base::Value>(true));
297 profile->GetTestingPrefService()->SetManagedPref(
298 prefs::kSafeBrowsingEnhanced, std::make_unique<base::Value>(false));
299 command_handler_ = std::make_unique<MockCommandHandler>(profile.get());
300
301 EXPECT_FALSE(CanShowPromoWithCommand(
302 Command::kOpenSafeBrowsingEnhancedProtectionSettings));
303 }
304
TEST_F(PromoBrowserCommandHandlerTest,CanShowSafeBrowsingEnhancedProtectionCommandPromo_HasSafeBrowsingManaged_EnhancedProtection)305 TEST_F(
306 PromoBrowserCommandHandlerTest,
307 CanShowSafeBrowsingEnhancedProtectionCommandPromo_HasSafeBrowsingManaged_EnhancedProtection) {
308 TestingProfile::Builder builder;
309 std::unique_ptr<TestingProfile> profile = builder.Build();
310 profile->GetTestingPrefService()->SetManagedPref(
311 prefs::kSafeBrowsingEnabled, std::make_unique<base::Value>(true));
312 profile->GetTestingPrefService()->SetManagedPref(
313 prefs::kSafeBrowsingEnhanced, std::make_unique<base::Value>(true));
314 command_handler_ = std::make_unique<MockCommandHandler>(profile.get());
315
316 EXPECT_FALSE(CanShowPromoWithCommand(
317 Command::kOpenSafeBrowsingEnhancedProtectionSettings));
318 }
319
TEST_F(PromoBrowserCommandHandlerTest,OpenSafeBrowsingEnhancedProtectionCommand)320 TEST_F(PromoBrowserCommandHandlerTest,
321 OpenSafeBrowsingEnhancedProtectionCommand) {
322 // The kOpenSafeBrowsingEnhancedProtectionSettings command opens a new
323 // settings window with the Safe Browsing settings with the Enhanced
324 // Protection section expanded, and the correct disposition.
325 ClickInfoPtr info = ClickInfo::New();
326 info->middle_button = true;
327 info->meta_key = true;
328 EXPECT_CALL(
329 *command_handler_,
330 NavigateToURL(GURL(chrome::GetSettingsUrl(
331 chrome::kSafeBrowsingEnhancedProtectionSubPage)),
332 DispositionFromClick(*info)));
333 EXPECT_TRUE(ExecuteCommand(
334 Command::kOpenSafeBrowsingEnhancedProtectionSettings, std::move(info)));
335 }
336