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/settings_api_bubble_controller.h"
13 #include "chrome/browser/extensions/suspicious_extension_bubble_controller.h"
14 #include "chrome/browser/extensions/test_extension_system.h"
15 #include "chrome/test/base/testing_profile.h"
16 #include "content/public/test/test_browser_thread_bundle.h"
17 #include "extensions/common/extension.h"
18 #include "extensions/common/extension_builder.h"
19 #include "extensions/common/feature_switch.h"
23 const char kId1
[] = "iccfkkhkfiphcjdakkmcjmkfboccmndk";
24 const char kId2
[] = "ajjhifimiemdpmophmkkkcijegphclbl";
25 const char kId3
[] = "ioibbbfddncmmabjmpokikkeiofalaek";
29 namespace extensions
{
34 : action_button_callback_count_(0),
35 dismiss_button_callback_count_(0),
36 link_click_callback_count_(0) {
39 // Returns how often the dismiss button has been called.
40 size_t action_click_count() {
41 return action_button_callback_count_
;
44 // Returns how often the dismiss button has been called.
45 size_t dismiss_click_count() {
46 return dismiss_button_callback_count_
;
49 // Returns how often the link has been clicked.
50 size_t link_click_count() {
51 return link_click_callback_count_
;
55 size_t action_button_callback_count_
;
56 size_t dismiss_button_callback_count_
;
57 size_t link_click_callback_count_
;
60 // A test class for the SuspiciousExtensionBubbleController.
61 class TestSuspiciousExtensionBubbleController
62 : public SuspiciousExtensionBubbleController
,
65 explicit TestSuspiciousExtensionBubbleController(Profile
* profile
)
66 : SuspiciousExtensionBubbleController(profile
) {
69 virtual void OnBubbleAction() OVERRIDE
{
70 ++action_button_callback_count_
;
71 SuspiciousExtensionBubbleController::OnBubbleAction();
74 virtual void OnBubbleDismiss() OVERRIDE
{
75 ++dismiss_button_callback_count_
;
76 SuspiciousExtensionBubbleController::OnBubbleDismiss();
79 virtual void OnLinkClicked() OVERRIDE
{
80 ++link_click_callback_count_
;
81 SuspiciousExtensionBubbleController::OnLinkClicked();
85 // A test class for the DevModeBubbleController.
86 class TestDevModeBubbleController
87 : public DevModeBubbleController
,
90 explicit TestDevModeBubbleController(Profile
* profile
)
91 : DevModeBubbleController(profile
) {
94 virtual void OnBubbleAction() OVERRIDE
{
95 ++action_button_callback_count_
;
96 DevModeBubbleController::OnBubbleAction();
99 virtual void OnBubbleDismiss() OVERRIDE
{
100 ++dismiss_button_callback_count_
;
101 DevModeBubbleController::OnBubbleDismiss();
104 virtual void OnLinkClicked() OVERRIDE
{
105 ++link_click_callback_count_
;
106 DevModeBubbleController::OnLinkClicked();
110 // A test class for the SettingsApiBubbleController.
111 class TestSettingsApiBubbleController
: public SettingsApiBubbleController
,
112 public TestDelegate
{
114 TestSettingsApiBubbleController(Profile
* profile
,
115 SettingsApiOverrideType type
)
116 : SettingsApiBubbleController(profile
, type
) {}
118 virtual void OnBubbleAction() OVERRIDE
{
119 ++action_button_callback_count_
;
120 SettingsApiBubbleController::OnBubbleAction();
123 virtual void OnBubbleDismiss() OVERRIDE
{
124 ++dismiss_button_callback_count_
;
125 SettingsApiBubbleController::OnBubbleDismiss();
128 virtual void OnLinkClicked() OVERRIDE
{
129 ++link_click_callback_count_
;
130 SettingsApiBubbleController::OnLinkClicked();
134 // A fake bubble used for testing the controller. Takes an action that specifies
135 // what should happen when the bubble is "shown" (the bubble is actually not
136 // shown, the corresponding action is taken immediately).
137 class FakeExtensionMessageBubble
: public ExtensionMessageBubble
{
139 enum ExtensionBubbleAction
{
140 BUBBLE_ACTION_CLICK_ACTION_BUTTON
= 0,
141 BUBBLE_ACTION_CLICK_DISMISS_BUTTON
,
142 BUBBLE_ACTION_CLICK_LINK
,
145 FakeExtensionMessageBubble() {}
147 void set_action_on_show(ExtensionBubbleAction action
) {
151 virtual void Show() OVERRIDE
{
152 if (action_
== BUBBLE_ACTION_CLICK_ACTION_BUTTON
)
153 action_callback_
.Run();
154 else if (action_
== BUBBLE_ACTION_CLICK_DISMISS_BUTTON
)
155 dismiss_callback_
.Run();
156 else if (action_
== BUBBLE_ACTION_CLICK_LINK
)
157 link_callback_
.Run();
160 virtual void OnActionButtonClicked(const base::Closure
& callback
) OVERRIDE
{
161 action_callback_
= callback
;
164 virtual void OnDismissButtonClicked(const base::Closure
& callback
) OVERRIDE
{
165 dismiss_callback_
= callback
;
168 virtual void OnLinkClicked(const base::Closure
& callback
) OVERRIDE
{
169 link_callback_
= callback
;
173 ExtensionBubbleAction action_
;
175 base::Closure action_callback_
;
176 base::Closure dismiss_callback_
;
177 base::Closure link_callback_
;
180 class ExtensionMessageBubbleTest
: public testing::Test
{
182 ExtensionMessageBubbleTest() {}
184 void LoadGenericExtension(const std::string
& index
,
185 const std::string
& id
,
186 Manifest::Location location
) {
187 extensions::ExtensionBuilder builder
;
188 builder
.SetManifest(extensions::DictionaryBuilder()
189 .Set("name", std::string("Extension " + index
))
190 .Set("version", "1.0")
191 .Set("manifest_version", 2));
192 builder
.SetLocation(location
);
194 service_
->AddExtension(builder
.Build().get());
197 void LoadExtensionWithAction(const std::string
& index
,
198 const std::string
& id
,
199 Manifest::Location location
) {
200 extensions::ExtensionBuilder builder
;
201 builder
.SetManifest(extensions::DictionaryBuilder()
202 .Set("name", std::string("Extension " + index
))
203 .Set("version", "1.0")
204 .Set("manifest_version", 2)
205 .Set("browser_action",
206 extensions::DictionaryBuilder().Set(
207 "default_title", "Default title")));
208 builder
.SetLocation(location
);
210 service_
->AddExtension(builder
.Build().get());
213 void LoadExtensionOverridingHome(const std::string
& index
,
214 const std::string
& id
,
215 Manifest::Location location
) {
216 extensions::ExtensionBuilder builder
;
217 builder
.SetManifest(extensions::DictionaryBuilder()
218 .Set("name", std::string("Extension " + index
))
219 .Set("version", "1.0")
220 .Set("manifest_version", 2)
221 .Set("chrome_settings_overrides",
222 extensions::DictionaryBuilder().Set(
223 "homepage", "http://www.google.com")));
224 builder
.SetLocation(location
);
226 service_
->AddExtension(builder
.Build().get());
229 void LoadExtensionOverridingStart(const std::string
& index
,
230 const std::string
& id
,
231 Manifest::Location location
) {
232 extensions::ExtensionBuilder builder
;
233 builder
.SetManifest(extensions::DictionaryBuilder()
234 .Set("name", std::string("Extension " + index
))
235 .Set("version", "1.0")
236 .Set("manifest_version", 2)
237 .Set("chrome_settings_overrides",
238 extensions::DictionaryBuilder().Set(
240 extensions::ListBuilder().Append(
241 "http://www.google.com"))));
242 builder
.SetLocation(location
);
244 service_
->AddExtension(builder
.Build().get());
248 // The two lines of magical incantation required to get the extension
249 // service to work inside a unit test and access the extension prefs.
250 thread_bundle_
.reset(new content::TestBrowserThreadBundle
);
251 profile_
.reset(new TestingProfile
);
252 static_cast<TestExtensionSystem
*>(
253 ExtensionSystem::Get(profile()))->CreateExtensionService(
254 CommandLine::ForCurrentProcess(),
257 service_
= profile_
->GetExtensionService();
261 virtual ~ExtensionMessageBubbleTest() {
262 // Make sure the profile is destroyed before the thread bundle.
263 profile_
.reset(NULL
);
266 virtual void SetUp() {
267 command_line_
.reset(new CommandLine(CommandLine::NO_PROGRAM
));
271 Profile
* profile() { return profile_
.get(); }
273 scoped_refptr
<Extension
> CreateExtension(
274 Manifest::Location location
,
275 const std::string
& data
,
276 const std::string
& id
) {
277 scoped_ptr
<base::DictionaryValue
> parsed_manifest(
278 extension_function_test_utils::ParseDictionary(data
));
279 return extension_function_test_utils::CreateExtension(
281 parsed_manifest
.get(),
285 ExtensionService
* service_
;
288 scoped_ptr
<CommandLine
> command_line_
;
289 scoped_ptr
<content::TestBrowserThreadBundle
> thread_bundle_
;
290 scoped_ptr
<TestingProfile
> profile_
;
292 DISALLOW_COPY_AND_ASSIGN(ExtensionMessageBubbleTest
);
295 // The feature this is meant to test is only implemented on Windows.
297 #define MAYBE_WipeoutControllerTest WipeoutControllerTest
299 #define MAYBE_WipeoutControllerTest DISABLED_WipeoutControllerTest
302 TEST_F(ExtensionMessageBubbleTest
, MAYBE_WipeoutControllerTest
) {
304 // Add three extensions, and control two of them in this test (extension 1
306 LoadExtensionWithAction("1", kId1
, Manifest::COMMAND_LINE
);
307 LoadGenericExtension("2", kId2
, Manifest::UNPACKED
);
308 LoadGenericExtension("3", kId3
, Manifest::EXTERNAL_POLICY
);
310 scoped_ptr
<TestSuspiciousExtensionBubbleController
> controller(
311 new TestSuspiciousExtensionBubbleController(profile()));
312 FakeExtensionMessageBubble bubble
;
313 bubble
.set_action_on_show(
314 FakeExtensionMessageBubble::BUBBLE_ACTION_CLICK_DISMISS_BUTTON
);
316 // Validate that we don't have a suppress value for the extensions.
317 ExtensionPrefs
* prefs
= ExtensionPrefs::Get(profile());
318 EXPECT_FALSE(prefs
->HasWipeoutBeenAcknowledged(kId1
));
319 EXPECT_FALSE(prefs
->HasWipeoutBeenAcknowledged(kId2
));
321 EXPECT_FALSE(controller
->ShouldShow());
322 std::vector
<base::string16
> suspicious_extensions
=
323 controller
->GetExtensionList();
324 EXPECT_EQ(0U, suspicious_extensions
.size());
325 EXPECT_EQ(0U, controller
->link_click_count());
326 EXPECT_EQ(0U, controller
->dismiss_click_count());
328 // Now disable an extension, specifying the wipeout flag.
329 service_
->DisableExtension(kId1
, Extension::DISABLE_NOT_VERIFIED
);
331 EXPECT_FALSE(prefs
->HasWipeoutBeenAcknowledged(kId1
));
332 EXPECT_FALSE(prefs
->HasWipeoutBeenAcknowledged(kId2
));
333 controller
.reset(new TestSuspiciousExtensionBubbleController(
335 SuspiciousExtensionBubbleController::ClearProfileListForTesting();
336 EXPECT_TRUE(controller
->ShouldShow());
337 suspicious_extensions
= controller
->GetExtensionList();
338 ASSERT_EQ(1U, suspicious_extensions
.size());
339 EXPECT_TRUE(base::ASCIIToUTF16("Extension 1") == suspicious_extensions
[0]);
340 controller
->Show(&bubble
); // Simulate showing the bubble.
341 EXPECT_EQ(0U, controller
->link_click_count());
342 EXPECT_EQ(1U, controller
->dismiss_click_count());
343 // Now the acknowledge flag should be set only for the first extension.
344 EXPECT_TRUE(prefs
->HasWipeoutBeenAcknowledged(kId1
));
345 EXPECT_FALSE(prefs
->HasWipeoutBeenAcknowledged(kId2
));
347 prefs
->SetWipeoutAcknowledged(kId1
, false);
348 EXPECT_FALSE(prefs
->HasWipeoutBeenAcknowledged(kId1
));
350 // Now disable the other extension and exercise the link click code path.
351 service_
->DisableExtension(kId2
, Extension::DISABLE_NOT_VERIFIED
);
353 bubble
.set_action_on_show(
354 FakeExtensionMessageBubble::BUBBLE_ACTION_CLICK_LINK
);
355 controller
.reset(new TestSuspiciousExtensionBubbleController(
357 SuspiciousExtensionBubbleController::ClearProfileListForTesting();
358 EXPECT_TRUE(controller
->ShouldShow());
359 suspicious_extensions
= controller
->GetExtensionList();
360 ASSERT_EQ(2U, suspicious_extensions
.size());
361 EXPECT_TRUE(base::ASCIIToUTF16("Extension 1") == suspicious_extensions
[1]);
362 EXPECT_TRUE(base::ASCIIToUTF16("Extension 2") == suspicious_extensions
[0]);
363 controller
->Show(&bubble
); // Simulate showing the bubble.
364 EXPECT_EQ(1U, controller
->link_click_count());
365 EXPECT_EQ(0U, controller
->dismiss_click_count());
366 EXPECT_TRUE(prefs
->HasWipeoutBeenAcknowledged(kId1
));
369 // The feature this is meant to test is only implemented on Windows.
371 #define MAYBE_DevModeControllerTest DevModeControllerTest
373 #define MAYBE_DevModeControllerTest DISABLED_DevModeControllerTest
376 TEST_F(ExtensionMessageBubbleTest
, MAYBE_DevModeControllerTest
) {
377 FeatureSwitch::ScopedOverride
force_dev_mode_highlighting(
378 FeatureSwitch::force_dev_mode_highlighting(), true);
380 // Add three extensions, and control two of them in this test (extension 1
381 // and 2). Extension 1 is a regular extension, Extension 2 is UNPACKED so it
382 // counts as a DevMode extension.
383 LoadExtensionWithAction("1", kId1
, Manifest::COMMAND_LINE
);
384 LoadGenericExtension("2", kId2
, Manifest::UNPACKED
);
385 LoadGenericExtension("3", kId3
, Manifest::EXTERNAL_POLICY
);
387 scoped_ptr
<TestDevModeBubbleController
> controller(
388 new TestDevModeBubbleController(profile()));
390 // The list will contain one enabled unpacked extension.
391 EXPECT_TRUE(controller
->ShouldShow());
392 std::vector
<base::string16
> dev_mode_extensions
=
393 controller
->GetExtensionList();
394 ASSERT_EQ(2U, dev_mode_extensions
.size());
395 EXPECT_TRUE(base::ASCIIToUTF16("Extension 2") == dev_mode_extensions
[0]);
396 EXPECT_TRUE(base::ASCIIToUTF16("Extension 1") == dev_mode_extensions
[1]);
397 EXPECT_EQ(0U, controller
->link_click_count());
398 EXPECT_EQ(0U, controller
->dismiss_click_count());
399 EXPECT_EQ(0U, controller
->action_click_count());
401 // Simulate showing the bubble.
402 FakeExtensionMessageBubble bubble
;
403 bubble
.set_action_on_show(
404 FakeExtensionMessageBubble::BUBBLE_ACTION_CLICK_DISMISS_BUTTON
);
405 controller
->Show(&bubble
);
406 EXPECT_EQ(0U, controller
->link_click_count());
407 EXPECT_EQ(0U, controller
->action_click_count());
408 EXPECT_EQ(1U, controller
->dismiss_click_count());
409 EXPECT_TRUE(service_
->GetExtensionById(kId1
, false) != NULL
);
410 EXPECT_TRUE(service_
->GetExtensionById(kId2
, false) != NULL
);
412 // Do it again, but now press different button (Disable).
413 bubble
.set_action_on_show(
414 FakeExtensionMessageBubble::BUBBLE_ACTION_CLICK_ACTION_BUTTON
);
415 controller
.reset(new TestDevModeBubbleController(
417 DevModeBubbleController::ClearProfileListForTesting();
418 EXPECT_TRUE(controller
->ShouldShow());
419 dev_mode_extensions
= controller
->GetExtensionList();
420 EXPECT_EQ(2U, dev_mode_extensions
.size());
421 controller
->Show(&bubble
); // Simulate showing the bubble.
422 EXPECT_EQ(0U, controller
->link_click_count());
423 EXPECT_EQ(1U, controller
->action_click_count());
424 EXPECT_EQ(0U, controller
->dismiss_click_count());
425 EXPECT_TRUE(service_
->GetExtensionById(kId1
, false) == NULL
);
426 EXPECT_TRUE(service_
->GetExtensionById(kId2
, false) == NULL
);
428 // Re-enable the extensions (disabled by the action button above).
429 service_
->EnableExtension(kId1
);
430 service_
->EnableExtension(kId2
);
432 // Show the dialog a third time, but now press the learn more link.
433 bubble
.set_action_on_show(
434 FakeExtensionMessageBubble::BUBBLE_ACTION_CLICK_LINK
);
435 controller
.reset(new TestDevModeBubbleController(
437 DevModeBubbleController::ClearProfileListForTesting();
438 EXPECT_TRUE(controller
->ShouldShow());
439 dev_mode_extensions
= controller
->GetExtensionList();
440 EXPECT_EQ(2U, dev_mode_extensions
.size());
441 controller
->Show(&bubble
); // Simulate showing the bubble.
442 EXPECT_EQ(1U, controller
->link_click_count());
443 EXPECT_EQ(0U, controller
->action_click_count());
444 EXPECT_EQ(0U, controller
->dismiss_click_count());
445 EXPECT_TRUE(service_
->GetExtensionById(kId1
, false) != NULL
);
446 EXPECT_TRUE(service_
->GetExtensionById(kId2
, false) != NULL
);
448 // Now disable the unpacked extension.
449 service_
->DisableExtension(kId1
, Extension::DISABLE_USER_ACTION
);
450 service_
->DisableExtension(kId2
, Extension::DISABLE_USER_ACTION
);
452 controller
.reset(new TestDevModeBubbleController(
454 DevModeBubbleController::ClearProfileListForTesting();
455 EXPECT_FALSE(controller
->ShouldShow());
456 dev_mode_extensions
= controller
->GetExtensionList();
457 EXPECT_EQ(0U, dev_mode_extensions
.size());
460 // The feature this is meant to test is only implemented on Windows.
462 #define MAYBE_SettingsApiControllerTest SettingsApiControllerTest
464 #define MAYBE_SettingsApiControllerTest DISABLED_SettingsApiControllerTest
467 TEST_F(ExtensionMessageBubbleTest
, MAYBE_SettingsApiControllerTest
) {
469 extensions::ExtensionPrefs
* prefs
=
470 extensions::ExtensionPrefs::Get(profile());
472 for (int i
= 0; i
< 3; ++i
) {
473 switch (static_cast<SettingsApiOverrideType
>(i
)) {
474 case BUBBLE_TYPE_HOME_PAGE
:
475 // Load two extensions overriding home page and one overriding something
476 // unrelated (to check for interference). Extension 2 should still win
477 // on the home page setting.
478 LoadExtensionOverridingHome("1", kId1
, Manifest::UNPACKED
);
479 LoadExtensionOverridingHome("2", kId2
, Manifest::UNPACKED
);
480 LoadExtensionOverridingStart("3", kId3
, Manifest::UNPACKED
);
482 case BUBBLE_TYPE_SEARCH_ENGINE
:
483 // We deliberately skip testing the search engine since it relies on
484 // TemplateURLServiceFactory that isn't available while unit testing.
485 // This test is only simulating the bubble interaction with the user and
486 // that is more or less the same for the search engine as it is for the
489 case BUBBLE_TYPE_STARTUP_PAGES
:
490 // Load two extensions overriding start page and one overriding
491 // something unrelated (to check for interference). Extension 2 should
492 // still win on the startup page setting.
493 LoadExtensionOverridingStart("1", kId1
, Manifest::UNPACKED
);
494 LoadExtensionOverridingStart("2", kId2
, Manifest::UNPACKED
);
495 LoadExtensionOverridingHome("3", kId3
, Manifest::UNPACKED
);
502 scoped_ptr
<TestSettingsApiBubbleController
> controller(
503 new TestSettingsApiBubbleController(
504 profile(), static_cast<SettingsApiOverrideType
>(i
)));
506 // The list will contain one enabled unpacked extension (ext 2).
507 EXPECT_TRUE(controller
->ShouldShow(kId2
));
508 std::vector
<base::string16
> override_extensions
=
509 controller
->GetExtensionList();
510 ASSERT_EQ(1U, override_extensions
.size());
511 EXPECT_TRUE(base::ASCIIToUTF16("Extension 2") ==
512 override_extensions
[0].c_str());
513 EXPECT_EQ(0U, controller
->link_click_count());
514 EXPECT_EQ(0U, controller
->dismiss_click_count());
515 EXPECT_EQ(0U, controller
->action_click_count());
517 // Simulate showing the bubble and dismissing it.
518 FakeExtensionMessageBubble bubble
;
519 bubble
.set_action_on_show(
520 FakeExtensionMessageBubble::BUBBLE_ACTION_CLICK_DISMISS_BUTTON
);
521 controller
->Show(&bubble
);
522 EXPECT_EQ(0U, controller
->link_click_count());
523 EXPECT_EQ(0U, controller
->action_click_count());
524 EXPECT_EQ(1U, controller
->dismiss_click_count());
525 // No extension should have become disabled.
526 EXPECT_TRUE(service_
->GetExtensionById(kId1
, false) != NULL
);
527 EXPECT_TRUE(service_
->GetExtensionById(kId2
, false) != NULL
);
528 EXPECT_TRUE(service_
->GetExtensionById(kId3
, false) != NULL
);
529 // Only extension 2 should have been acknowledged.
530 EXPECT_FALSE(prefs
->HasSettingsApiBubbleBeenAcknowledged(kId1
));
531 EXPECT_TRUE(prefs
->HasSettingsApiBubbleBeenAcknowledged(kId2
));
532 EXPECT_FALSE(prefs
->HasSettingsApiBubbleBeenAcknowledged(kId3
));
533 // Clean up after ourselves.
534 prefs
->SetSettingsApiBubbleBeenAcknowledged(kId2
, false);
536 // Simulate clicking the learn more link to dismiss it.
537 bubble
.set_action_on_show(
538 FakeExtensionMessageBubble::BUBBLE_ACTION_CLICK_LINK
);
539 controller
.reset(new TestSettingsApiBubbleController(
540 profile(), static_cast<SettingsApiOverrideType
>(i
)));
541 controller
->Show(&bubble
);
542 EXPECT_EQ(1U, controller
->link_click_count());
543 EXPECT_EQ(0U, controller
->action_click_count());
544 EXPECT_EQ(0U, controller
->dismiss_click_count());
545 // No extension should have become disabled.
546 EXPECT_TRUE(service_
->GetExtensionById(kId1
, false) != NULL
);
547 EXPECT_TRUE(service_
->GetExtensionById(kId2
, false) != NULL
);
548 EXPECT_TRUE(service_
->GetExtensionById(kId3
, false) != NULL
);
549 // Only extension 2 should have been acknowledged.
550 EXPECT_FALSE(prefs
->HasSettingsApiBubbleBeenAcknowledged(kId1
));
551 EXPECT_TRUE(prefs
->HasSettingsApiBubbleBeenAcknowledged(kId2
));
552 EXPECT_FALSE(prefs
->HasSettingsApiBubbleBeenAcknowledged(kId3
));
553 // Clean up after ourselves.
554 prefs
->SetSettingsApiBubbleBeenAcknowledged(kId2
, false);
556 // Do it again, but now opt to disable the extension.
557 bubble
.set_action_on_show(
558 FakeExtensionMessageBubble::BUBBLE_ACTION_CLICK_ACTION_BUTTON
);
559 controller
.reset(new TestSettingsApiBubbleController(
560 profile(), static_cast<SettingsApiOverrideType
>(i
)));
561 EXPECT_TRUE(controller
->ShouldShow(kId2
));
562 override_extensions
= controller
->GetExtensionList();
563 EXPECT_EQ(1U, override_extensions
.size());
564 controller
->Show(&bubble
); // Simulate showing the bubble.
565 EXPECT_EQ(0U, controller
->link_click_count());
566 EXPECT_EQ(1U, controller
->action_click_count());
567 EXPECT_EQ(0U, controller
->dismiss_click_count());
568 // Only extension 2 should have become disabled.
569 EXPECT_TRUE(service_
->GetExtensionById(kId1
, false) != NULL
);
570 EXPECT_TRUE(service_
->GetExtensionById(kId2
, false) == NULL
);
571 EXPECT_TRUE(service_
->GetExtensionById(kId3
, false) != NULL
);
572 // No extension should have been acknowledged (it got disabled).
573 EXPECT_FALSE(prefs
->HasSettingsApiBubbleBeenAcknowledged(kId1
));
574 EXPECT_FALSE(prefs
->HasSettingsApiBubbleBeenAcknowledged(kId2
));
575 EXPECT_FALSE(prefs
->HasSettingsApiBubbleBeenAcknowledged(kId3
));
577 // Clean up after ourselves.
578 service_
->UninstallExtension(kId1
, false, NULL
);
579 service_
->UninstallExtension(kId2
, false, NULL
);
580 service_
->UninstallExtension(kId3
, false, NULL
);
584 } // namespace extensions