1 // Copyright (c) 2013 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.
5 #include "base/command_line.h"
6 #include "base/strings/string_util.h"
7 #include "base/strings/utf_string_conversions.h"
8 #include "chrome/browser/extensions/dev_mode_bubble_controller.h"
9 #include "chrome/browser/extensions/extension_function_test_utils.h"
10 #include "chrome/browser/extensions/extension_message_bubble.h"
11 #include "chrome/browser/extensions/extension_service.h"
12 #include "chrome/browser/extensions/suspicious_extension_bubble_controller.h"
13 #include "chrome/browser/extensions/test_extension_system.h"
14 #include "chrome/test/base/testing_profile.h"
15 #include "content/public/test/test_browser_thread_bundle.h"
16 #include "extensions/common/extension.h"
17 #include "extensions/common/feature_switch.h"
19 namespace extensions
{
24 : action_button_callback_count_(0),
25 dismiss_button_callback_count_(0),
26 link_click_callback_count_(0) {
29 // Returns how often the dismiss button has been called.
30 size_t action_click_count() {
31 return action_button_callback_count_
;
34 // Returns how often the dismiss button has been called.
35 size_t dismiss_click_count() {
36 return dismiss_button_callback_count_
;
39 // Returns how often the link has been clicked.
40 size_t link_click_count() {
41 return link_click_callback_count_
;
45 size_t action_button_callback_count_
;
46 size_t dismiss_button_callback_count_
;
47 size_t link_click_callback_count_
;
50 // A test class for the SuspiciousExtensionBubbleController.
51 class TestSuspiciousExtensionBubbleController
52 : public SuspiciousExtensionBubbleController
,
55 explicit TestSuspiciousExtensionBubbleController(Profile
* profile
)
56 : SuspiciousExtensionBubbleController(profile
) {
59 virtual void OnBubbleAction() OVERRIDE
{
60 ++action_button_callback_count_
;
61 SuspiciousExtensionBubbleController::OnBubbleAction();
64 virtual void OnBubbleDismiss() OVERRIDE
{
65 ++dismiss_button_callback_count_
;
66 SuspiciousExtensionBubbleController::OnBubbleDismiss();
69 virtual void OnLinkClicked() OVERRIDE
{
70 ++link_click_callback_count_
;
71 SuspiciousExtensionBubbleController::OnLinkClicked();
75 // A test class for the DevModeBubbleController.
76 class TestDevModeBubbleController
77 : public DevModeBubbleController
,
80 explicit TestDevModeBubbleController(Profile
* profile
)
81 : DevModeBubbleController(profile
) {
84 virtual void OnBubbleAction() OVERRIDE
{
85 ++action_button_callback_count_
;
86 DevModeBubbleController::OnBubbleAction();
89 virtual void OnBubbleDismiss() OVERRIDE
{
90 ++dismiss_button_callback_count_
;
91 DevModeBubbleController::OnBubbleDismiss();
94 virtual void OnLinkClicked() OVERRIDE
{
95 ++link_click_callback_count_
;
96 DevModeBubbleController::OnLinkClicked();
100 // A fake bubble used for testing the controller. Takes an action that specifies
101 // what should happen when the bubble is "shown" (the bubble is actually not
102 // shown, the corresponding action is taken immediately).
103 class FakeExtensionMessageBubble
: public ExtensionMessageBubble
{
105 enum ExtensionBubbleAction
{
106 BUBBLE_ACTION_CLICK_ACTION_BUTTON
= 0,
107 BUBBLE_ACTION_CLICK_DISMISS_BUTTON
,
108 BUBBLE_ACTION_CLICK_LINK
,
111 FakeExtensionMessageBubble() {}
113 void set_action_on_show(ExtensionBubbleAction action
) {
117 virtual void Show() OVERRIDE
{
118 if (action_
== BUBBLE_ACTION_CLICK_ACTION_BUTTON
)
119 action_callback_
.Run();
120 else if (action_
== BUBBLE_ACTION_CLICK_DISMISS_BUTTON
)
121 dismiss_callback_
.Run();
122 else if (action_
== BUBBLE_ACTION_CLICK_LINK
)
123 link_callback_
.Run();
126 virtual void OnActionButtonClicked(const base::Closure
& callback
) OVERRIDE
{
127 action_callback_
= callback
;
130 virtual void OnDismissButtonClicked(const base::Closure
& callback
) OVERRIDE
{
131 dismiss_callback_
= callback
;
134 virtual void OnLinkClicked(const base::Closure
& callback
) OVERRIDE
{
135 link_callback_
= callback
;
139 ExtensionBubbleAction action_
;
141 base::Closure action_callback_
;
142 base::Closure dismiss_callback_
;
143 base::Closure link_callback_
;
146 class ExtensionMessageBubbleTest
: public testing::Test
{
148 ExtensionMessageBubbleTest() {
149 // The two lines of magical incantation required to get the extension
150 // service to work inside a unit test and access the extension prefs.
151 thread_bundle_
.reset(new content::TestBrowserThreadBundle
);
152 profile_
.reset(new TestingProfile
);
154 static_cast<TestExtensionSystem
*>(
155 ExtensionSystem::Get(profile()))->CreateExtensionService(
156 CommandLine::ForCurrentProcess(),
159 service_
= profile_
->GetExtensionService();
162 std::string basic_extension
=
163 "{\"name\": \"Extension #\","
164 "\"version\": \"1.0\","
165 "\"manifest_version\": 2}";
166 std::string basic_extension_with_action
=
167 "{\"name\": \"Extension #\","
168 "\"version\": \"1.0\","
169 "\"browser_action\": {"
170 " \"default_title\": \"Default title\""
172 "\"manifest_version\": 2}";
174 std::string extension_data
;
175 base::ReplaceChars(basic_extension_with_action
, "#", "1", &extension_data
);
176 scoped_refptr
<Extension
> my_test_extension1(
178 Manifest::COMMAND_LINE
,
182 base::ReplaceChars(basic_extension
, "#", "2", &extension_data
);
183 scoped_refptr
<Extension
> my_test_extension2(
189 base::ReplaceChars(basic_extension
, "#", "3", &extension_data
);
190 scoped_refptr
<Extension
> regular_extension(
192 Manifest::EXTERNAL_POLICY
,
196 extension_id1_
= my_test_extension1
->id();
197 extension_id2_
= my_test_extension2
->id();
198 extension_id3_
= regular_extension
->id();
200 service_
->AddExtension(regular_extension
);
201 service_
->AddExtension(my_test_extension1
);
202 service_
->AddExtension(my_test_extension2
);
204 virtual ~ExtensionMessageBubbleTest() {
205 // Make sure the profile is destroyed before the thread bundle.
206 profile_
.reset(NULL
);
209 virtual void SetUp() {
210 command_line_
.reset(new CommandLine(CommandLine::NO_PROGRAM
));
214 Profile
* profile() { return profile_
.get(); }
216 scoped_refptr
<Extension
> CreateExtension(
217 Manifest::Location location
,
218 const std::string
& data
,
219 const std::string
& id
) {
220 scoped_ptr
<base::DictionaryValue
> parsed_manifest(
221 extension_function_test_utils::ParseDictionary(data
));
222 return extension_function_test_utils::CreateExtension(
224 parsed_manifest
.get(),
228 ExtensionService
* service_
;
229 std::string extension_id1_
;
230 std::string extension_id2_
;
231 std::string extension_id3_
;
234 scoped_ptr
<CommandLine
> command_line_
;
235 scoped_ptr
<content::TestBrowserThreadBundle
> thread_bundle_
;
236 scoped_ptr
<TestingProfile
> profile_
;
238 DISALLOW_COPY_AND_ASSIGN(ExtensionMessageBubbleTest
);
241 // The feature this is meant to test is only implemented on Windows.
243 #define MAYBE_WipeoutControllerTest WipeoutControllerTest
245 #define MAYBE_WipeoutControllerTest DISABLED_WipeoutControllerTest
248 TEST_F(ExtensionMessageBubbleTest
, MAYBE_WipeoutControllerTest
) {
249 // The test base class adds three extensions, and we control two of them in
250 // this test (ids are: extension_id1_ and extension_id2_).
251 scoped_ptr
<TestSuspiciousExtensionBubbleController
> controller(
252 new TestSuspiciousExtensionBubbleController(profile()));
253 FakeExtensionMessageBubble bubble
;
254 bubble
.set_action_on_show(
255 FakeExtensionMessageBubble::BUBBLE_ACTION_CLICK_DISMISS_BUTTON
);
257 // Validate that we don't have a suppress value for the extensions.
258 ExtensionPrefs
* prefs
= service_
->extension_prefs();
259 EXPECT_FALSE(prefs
->HasWipeoutBeenAcknowledged(extension_id1_
));
260 EXPECT_FALSE(prefs
->HasWipeoutBeenAcknowledged(extension_id2_
));
262 EXPECT_FALSE(controller
->ShouldShow());
263 std::vector
<base::string16
> suspicious_extensions
=
264 controller
->GetExtensionList();
265 EXPECT_EQ(0U, suspicious_extensions
.size());
266 EXPECT_EQ(0U, controller
->link_click_count());
267 EXPECT_EQ(0U, controller
->dismiss_click_count());
269 // Now disable an extension, specifying the wipeout flag.
270 service_
->DisableExtension(extension_id1_
,
271 Extension::DISABLE_NOT_VERIFIED
);
273 EXPECT_FALSE(prefs
->HasWipeoutBeenAcknowledged(extension_id1_
));
274 EXPECT_FALSE(prefs
->HasWipeoutBeenAcknowledged(extension_id2_
));
275 controller
.reset(new TestSuspiciousExtensionBubbleController(
277 SuspiciousExtensionBubbleController::ClearProfileListForTesting();
278 EXPECT_TRUE(controller
->ShouldShow());
279 suspicious_extensions
= controller
->GetExtensionList();
280 ASSERT_EQ(1U, suspicious_extensions
.size());
281 EXPECT_TRUE(base::ASCIIToUTF16("Extension 1") == suspicious_extensions
[0]);
282 controller
->Show(&bubble
); // Simulate showing the bubble.
283 EXPECT_EQ(0U, controller
->link_click_count());
284 EXPECT_EQ(1U, controller
->dismiss_click_count());
285 // Now the acknowledge flag should be set only for the first extension.
286 EXPECT_TRUE(prefs
->HasWipeoutBeenAcknowledged(extension_id1_
));
287 EXPECT_FALSE(prefs
->HasWipeoutBeenAcknowledged(extension_id2_
));
289 prefs
->SetWipeoutAcknowledged(extension_id1_
, false);
290 EXPECT_FALSE(prefs
->HasWipeoutBeenAcknowledged(extension_id1_
));
292 // Now disable the other extension and exercise the link click code path.
293 service_
->DisableExtension(extension_id2_
,
294 Extension::DISABLE_NOT_VERIFIED
);
296 bubble
.set_action_on_show(
297 FakeExtensionMessageBubble::BUBBLE_ACTION_CLICK_LINK
);
298 controller
.reset(new TestSuspiciousExtensionBubbleController(
300 SuspiciousExtensionBubbleController::ClearProfileListForTesting();
301 EXPECT_TRUE(controller
->ShouldShow());
302 suspicious_extensions
= controller
->GetExtensionList();
303 ASSERT_EQ(2U, suspicious_extensions
.size());
304 EXPECT_TRUE(base::ASCIIToUTF16("Extension 1") == suspicious_extensions
[1]);
305 EXPECT_TRUE(base::ASCIIToUTF16("Extension 2") == suspicious_extensions
[0]);
306 controller
->Show(&bubble
); // Simulate showing the bubble.
307 EXPECT_EQ(1U, controller
->link_click_count());
308 EXPECT_EQ(0U, controller
->dismiss_click_count());
309 EXPECT_TRUE(prefs
->HasWipeoutBeenAcknowledged(extension_id1_
));
312 // The feature this is meant to test is only implemented on Windows.
314 #define MAYBE_DevModeControllerTest DevModeControllerTest
316 #define MAYBE_DevModeControllerTest DISABLED_DevModeControllerTest
319 TEST_F(ExtensionMessageBubbleTest
, MAYBE_DevModeControllerTest
) {
320 FeatureSwitch::ScopedOverride
force_dev_mode_highlighting(
321 FeatureSwitch::force_dev_mode_highlighting(), true);
322 // The test base class adds three extensions, and we control two of them in
323 // this test (ids are: extension_id1_ and extension_id2_). Extension 1 is a
324 // regular extension, Extension 2 is UNPACKED so it counts as a DevMode
326 scoped_ptr
<TestDevModeBubbleController
> controller(
327 new TestDevModeBubbleController(profile()));
329 // The list will contain one enabled unpacked extension.
330 EXPECT_TRUE(controller
->ShouldShow());
331 std::vector
<base::string16
> dev_mode_extensions
=
332 controller
->GetExtensionList();
333 ASSERT_EQ(2U, dev_mode_extensions
.size());
334 EXPECT_TRUE(base::ASCIIToUTF16("Extension 2") == dev_mode_extensions
[0]);
335 EXPECT_TRUE(base::ASCIIToUTF16("Extension 1") == dev_mode_extensions
[1]);
336 EXPECT_EQ(0U, controller
->link_click_count());
337 EXPECT_EQ(0U, controller
->dismiss_click_count());
338 EXPECT_EQ(0U, controller
->action_click_count());
340 // Simulate showing the bubble.
341 FakeExtensionMessageBubble bubble
;
342 bubble
.set_action_on_show(
343 FakeExtensionMessageBubble::BUBBLE_ACTION_CLICK_DISMISS_BUTTON
);
344 controller
->Show(&bubble
);
345 EXPECT_EQ(0U, controller
->link_click_count());
346 EXPECT_EQ(0U, controller
->action_click_count());
347 EXPECT_EQ(1U, controller
->dismiss_click_count());
348 EXPECT_TRUE(service_
->GetExtensionById(extension_id1_
, false) != NULL
);
349 EXPECT_TRUE(service_
->GetExtensionById(extension_id2_
, false) != NULL
);
351 // Do it again, but now press different button (Disable).
352 bubble
.set_action_on_show(
353 FakeExtensionMessageBubble::BUBBLE_ACTION_CLICK_ACTION_BUTTON
);
354 controller
.reset(new TestDevModeBubbleController(
356 DevModeBubbleController::ClearProfileListForTesting();
357 EXPECT_TRUE(controller
->ShouldShow());
358 dev_mode_extensions
= controller
->GetExtensionList();
359 EXPECT_EQ(2U, dev_mode_extensions
.size());
360 controller
->Show(&bubble
); // Simulate showing the bubble.
361 EXPECT_EQ(0U, controller
->link_click_count());
362 EXPECT_EQ(1U, controller
->action_click_count());
363 EXPECT_EQ(0U, controller
->dismiss_click_count());
364 EXPECT_TRUE(service_
->GetExtensionById(extension_id1_
, false) == NULL
);
365 EXPECT_TRUE(service_
->GetExtensionById(extension_id2_
, false) == NULL
);
367 // Re-enable the extensions (disabled by the action button above).
368 service_
->EnableExtension(extension_id1_
);
369 service_
->EnableExtension(extension_id2_
);
371 // Show the dialog a third time, but now press the learn more link.
372 bubble
.set_action_on_show(
373 FakeExtensionMessageBubble::BUBBLE_ACTION_CLICK_LINK
);
374 controller
.reset(new TestDevModeBubbleController(
376 DevModeBubbleController::ClearProfileListForTesting();
377 EXPECT_TRUE(controller
->ShouldShow());
378 dev_mode_extensions
= controller
->GetExtensionList();
379 EXPECT_EQ(2U, dev_mode_extensions
.size());
380 controller
->Show(&bubble
); // Simulate showing the bubble.
381 EXPECT_EQ(1U, controller
->link_click_count());
382 EXPECT_EQ(0U, controller
->action_click_count());
383 EXPECT_EQ(0U, controller
->dismiss_click_count());
384 EXPECT_TRUE(service_
->GetExtensionById(extension_id1_
, false) != NULL
);
385 EXPECT_TRUE(service_
->GetExtensionById(extension_id2_
, false) != NULL
);
387 // Now disable the unpacked extension.
388 service_
->DisableExtension(extension_id1_
, Extension::DISABLE_USER_ACTION
);
389 service_
->DisableExtension(extension_id2_
, Extension::DISABLE_USER_ACTION
);
391 controller
.reset(new TestDevModeBubbleController(
393 DevModeBubbleController::ClearProfileListForTesting();
394 EXPECT_FALSE(controller
->ShouldShow());
395 dev_mode_extensions
= controller
->GetExtensionList();
396 EXPECT_EQ(0U, dev_mode_extensions
.size());
399 } // namespace extensions