1 // Copyright (c) 2011 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 "chrome/browser/extensions/extension_browsertest.h" 6 #include "chrome/browser/extensions/extension_toolbar_model.h" 7 #include "chrome/browser/profiles/profile.h" 8 #include "chrome/browser/ui/browser.h" 9 #include "chrome/test/base/in_process_browser_test.h" 10 11 using extensions::Extension; 12 13 // An InProcessBrowserTest for testing the ExtensionToolbarModel. 14 // TODO(erikkay) It's unfortunate that this needs to be an in-proc browser test. 15 // It would be nice to refactor things so that ExtensionService could run 16 // without so much of the browser in place. 17 class ExtensionToolbarModelTest : public ExtensionBrowserTest, 18 public ExtensionToolbarModel::Observer { 19 public: 20 virtual void SetUp() { 21 inserted_count_ = 0; 22 removed_count_ = 0; 23 moved_count_ = 0; 24 25 ExtensionBrowserTest::SetUp(); 26 } 27 28 virtual void SetUpOnMainThread() OVERRIDE { 29 model_ = ExtensionToolbarModel::Get(browser()->profile()); 30 model_->AddObserver(this); 31 } 32 33 virtual void CleanUpOnMainThread() OVERRIDE { 34 model_->RemoveObserver(this); 35 } 36 37 virtual void BrowserActionAdded(const Extension* extension, 38 int index) OVERRIDE { 39 inserted_count_++; 40 } 41 42 virtual void BrowserActionRemoved(const Extension* extension) OVERRIDE { 43 removed_count_++; 44 } 45 46 virtual void BrowserActionMoved(const Extension* extension, 47 int index) OVERRIDE { 48 moved_count_++; 49 } 50 51 const Extension* ExtensionAt(int index) { 52 const extensions::ExtensionList& toolbar_items = model_->toolbar_items(); 53 for (extensions::ExtensionList::const_iterator i = toolbar_items.begin(); 54 i < toolbar_items.end(); ++i) { 55 if (index-- == 0) 56 return i->get(); 57 } 58 return NULL; 59 } 60 61 protected: 62 ExtensionToolbarModel* model_; 63 64 int inserted_count_; 65 int removed_count_; 66 int moved_count_; 67 }; 68 69 IN_PROC_BROWSER_TEST_F(ExtensionToolbarModelTest, Basic) { 70 // Load an extension with no browser action. 71 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test") 72 .AppendASCII("browser_action") 73 .AppendASCII("none"))); 74 75 // This extension should not be in the model (has no browser action). 76 EXPECT_EQ(0, inserted_count_); 77 EXPECT_EQ(0u, model_->toolbar_items().size()); 78 ASSERT_EQ(NULL, ExtensionAt(0)); 79 80 // Load an extension with a browser action. 81 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test") 82 .AppendASCII("browser_action") 83 .AppendASCII("basics"))); 84 85 // We should now find our extension in the model. 86 EXPECT_EQ(1, inserted_count_); 87 EXPECT_EQ(1u, model_->toolbar_items().size()); 88 const Extension* extension = ExtensionAt(0); 89 ASSERT_TRUE(NULL != extension); 90 EXPECT_STREQ("A browser action with no icon that makes the page red", 91 extension->name().c_str()); 92 93 // Should be a no-op, but still fires the events. 94 model_->MoveBrowserAction(extension, 0); 95 EXPECT_EQ(1, moved_count_); 96 EXPECT_EQ(1u, model_->toolbar_items().size()); 97 const Extension* extension2 = ExtensionAt(0); 98 EXPECT_EQ(extension, extension2); 99 100 UnloadExtension(extension->id()); 101 EXPECT_EQ(1, removed_count_); 102 EXPECT_EQ(0u, model_->toolbar_items().size()); 103 EXPECT_EQ(NULL, ExtensionAt(0)); 104 } 105 106 #if defined(OS_MACOSX) 107 // Flaky on Mac 10.8 Blink canary bots: http://crbug.com/166580 108 #define MAYBE_ReorderAndReinsert DISABLED_ReorderAndReinsert 109 #else 110 #define MAYBE_ReorderAndReinsert ReorderAndReinsert 111 #endif 112 IN_PROC_BROWSER_TEST_F(ExtensionToolbarModelTest, MAYBE_ReorderAndReinsert) { 113 // Load an extension with a browser action. 114 base::FilePath extension_a_path(test_data_dir_.AppendASCII("api_test") 115 .AppendASCII("browser_action") 116 .AppendASCII("basics")); 117 ASSERT_TRUE(LoadExtension(extension_a_path)); 118 119 // First extension loaded. 120 EXPECT_EQ(1, inserted_count_); 121 EXPECT_EQ(1u, model_->toolbar_items().size()); 122 const Extension* extensionA = ExtensionAt(0); 123 ASSERT_TRUE(NULL != extensionA); 124 EXPECT_STREQ("A browser action with no icon that makes the page red", 125 extensionA->name().c_str()); 126 127 // Load another extension with a browser action. 128 base::FilePath extension_b_path(test_data_dir_.AppendASCII("api_test") 129 .AppendASCII("browser_action") 130 .AppendASCII("popup")); 131 ASSERT_TRUE(LoadExtension(extension_b_path)); 132 133 // Second extension loaded. 134 EXPECT_EQ(2, inserted_count_); 135 EXPECT_EQ(2u, model_->toolbar_items().size()); 136 const Extension* extensionB = ExtensionAt(1); 137 ASSERT_TRUE(NULL != extensionB); 138 EXPECT_STREQ("Popup tester", extensionB->name().c_str()); 139 140 // Load yet another extension with a browser action. 141 base::FilePath extension_c_path(test_data_dir_.AppendASCII("api_test") 142 .AppendASCII("browser_action") 143 .AppendASCII("remove_popup")); 144 ASSERT_TRUE(LoadExtension(extension_c_path)); 145 146 // Third extension loaded. 147 EXPECT_EQ(3, inserted_count_); 148 EXPECT_EQ(3u, model_->toolbar_items().size()); 149 const Extension* extensionC = ExtensionAt(2); 150 ASSERT_TRUE(NULL != extensionC); 151 EXPECT_STREQ("A page action which removes a popup.", 152 extensionC->name().c_str()); 153 154 // Order is now A, B, C. Let's put C first. 155 model_->MoveBrowserAction(extensionC, 0); 156 EXPECT_EQ(1, moved_count_); 157 EXPECT_EQ(3u, model_->toolbar_items().size()); 158 EXPECT_EQ(extensionC, ExtensionAt(0)); 159 EXPECT_EQ(extensionA, ExtensionAt(1)); 160 EXPECT_EQ(extensionB, ExtensionAt(2)); 161 EXPECT_EQ(NULL, ExtensionAt(3)); 162 163 // Order is now C, A, B. Let's put A last. 164 model_->MoveBrowserAction(extensionA, 2); 165 EXPECT_EQ(2, moved_count_); 166 EXPECT_EQ(3u, model_->toolbar_items().size()); 167 EXPECT_EQ(extensionC, ExtensionAt(0)); 168 EXPECT_EQ(extensionB, ExtensionAt(1)); 169 EXPECT_EQ(extensionA, ExtensionAt(2)); 170 EXPECT_EQ(NULL, ExtensionAt(3)); 171 172 // Order is now C, B, A. Let's remove B. 173 std::string idB = extensionB->id(); 174 UnloadExtension(idB); 175 EXPECT_EQ(1, removed_count_); 176 EXPECT_EQ(2u, model_->toolbar_items().size()); 177 EXPECT_EQ(extensionC, ExtensionAt(0)); 178 EXPECT_EQ(extensionA, ExtensionAt(1)); 179 EXPECT_EQ(NULL, ExtensionAt(2)); 180 181 // Load extension B again. 182 ASSERT_TRUE(LoadExtension(extension_b_path)); 183 184 // Extension B loaded again. 185 EXPECT_EQ(4, inserted_count_); 186 EXPECT_EQ(3u, model_->toolbar_items().size()); 187 // Make sure it gets its old spot in the list. We should get the same 188 // extension again, otherwise the order has changed. 189 ASSERT_STREQ(idB.c_str(), ExtensionAt(1)->id().c_str()); 190 191 // Unload B again. 192 UnloadExtension(idB); 193 EXPECT_EQ(2, removed_count_); 194 EXPECT_EQ(2u, model_->toolbar_items().size()); 195 EXPECT_EQ(extensionC, ExtensionAt(0)); 196 EXPECT_EQ(extensionA, ExtensionAt(1)); 197 EXPECT_EQ(NULL, ExtensionAt(2)); 198 199 // Order is now C, A. Flip it. 200 model_->MoveBrowserAction(extensionA, 0); 201 EXPECT_EQ(3, moved_count_); 202 EXPECT_EQ(2u, model_->toolbar_items().size()); 203 EXPECT_EQ(extensionA, ExtensionAt(0)); 204 EXPECT_EQ(extensionC, ExtensionAt(1)); 205 EXPECT_EQ(NULL, ExtensionAt(2)); 206 207 // Move A to the location it already occupies. 208 model_->MoveBrowserAction(extensionA, 0); 209 EXPECT_EQ(4, moved_count_); 210 EXPECT_EQ(2u, model_->toolbar_items().size()); 211 EXPECT_EQ(extensionA, ExtensionAt(0)); 212 EXPECT_EQ(extensionC, ExtensionAt(1)); 213 EXPECT_EQ(NULL, ExtensionAt(2)); 214 215 // Order is now A, C. Remove C. 216 std::string idC = extensionC->id(); 217 UnloadExtension(idC); 218 EXPECT_EQ(3, removed_count_); 219 EXPECT_EQ(1u, model_->toolbar_items().size()); 220 EXPECT_EQ(extensionA, ExtensionAt(0)); 221 EXPECT_EQ(NULL, ExtensionAt(1)); 222 223 // Load extension C again. 224 ASSERT_TRUE(LoadExtension(extension_c_path)); 225 226 // Extension C loaded again. 227 EXPECT_EQ(5, inserted_count_); 228 EXPECT_EQ(2u, model_->toolbar_items().size()); 229 // Make sure it gets its old spot in the list (at the very end). 230 ASSERT_STREQ(idC.c_str(), ExtensionAt(1)->id().c_str()); 231 } 232 233 IN_PROC_BROWSER_TEST_F(ExtensionToolbarModelTest, UnloadAndDisableMultiple) { 234 // Load three extensions with browser action. 235 base::FilePath extension_a_path(test_data_dir_.AppendASCII("api_test") 236 .AppendASCII("browser_action") 237 .AppendASCII("basics")); 238 ASSERT_TRUE(LoadExtension(extension_a_path)); 239 base::FilePath extension_b_path(test_data_dir_.AppendASCII("api_test") 240 .AppendASCII("browser_action") 241 .AppendASCII("popup")); 242 ASSERT_TRUE(LoadExtension(extension_b_path)); 243 base::FilePath extension_c_path(test_data_dir_.AppendASCII("api_test") 244 .AppendASCII("browser_action") 245 .AppendASCII("remove_popup")); 246 ASSERT_TRUE(LoadExtension(extension_c_path)); 247 248 // Verify we got the three we asked for and that they are ordered as: A, B, C. 249 const Extension* extensionA = ExtensionAt(0); 250 const Extension* extensionB = ExtensionAt(1); 251 const Extension* extensionC = ExtensionAt(2); 252 std::string idA = extensionA->id(); 253 std::string idB = extensionB->id(); 254 std::string idC = extensionC->id(); 255 EXPECT_STREQ("A browser action with no icon that makes the page red", 256 extensionA->name().c_str()); 257 EXPECT_STREQ("Popup tester", extensionB->name().c_str()); 258 EXPECT_STREQ("A page action which removes a popup.", 259 extensionC->name().c_str()); 260 261 // Unload B, then C, then A. 262 UnloadExtension(idB); 263 UnloadExtension(idC); 264 UnloadExtension(idA); 265 266 // Load C, then A, then B. 267 ASSERT_TRUE(LoadExtension(extension_c_path)); 268 ASSERT_TRUE(LoadExtension(extension_a_path)); 269 ASSERT_TRUE(LoadExtension(extension_b_path)); 270 EXPECT_EQ(0, moved_count_); 271 272 extensionA = ExtensionAt(0); 273 extensionB = ExtensionAt(1); 274 extensionC = ExtensionAt(2); 275 276 // Make sure we get the order we started with (A, B, C). 277 EXPECT_STREQ(idA.c_str(), extensionA->id().c_str()); 278 EXPECT_STREQ(idB.c_str(), extensionB->id().c_str()); 279 EXPECT_STREQ(idC.c_str(), extensionC->id().c_str()); 280 281 // Put C in the middle and A to the end. 282 model_->MoveBrowserAction(extensionC, 1); 283 model_->MoveBrowserAction(extensionA, 2); 284 285 // Make sure we get this order (C, B, A). 286 EXPECT_STREQ(idC.c_str(), ExtensionAt(0)->id().c_str()); 287 EXPECT_STREQ(idB.c_str(), ExtensionAt(1)->id().c_str()); 288 EXPECT_STREQ(idA.c_str(), ExtensionAt(2)->id().c_str()); 289 290 // Disable B, then C, then A. 291 DisableExtension(idB); 292 DisableExtension(idC); 293 DisableExtension(idA); 294 295 // Enable C, then A, then B. 296 EnableExtension(idA); 297 EnableExtension(idB); 298 EnableExtension(idC); 299 300 // Make sure we get the order we started with. 301 EXPECT_STREQ(idC.c_str(), ExtensionAt(0)->id().c_str()); 302 EXPECT_STREQ(idB.c_str(), ExtensionAt(1)->id().c_str()); 303 EXPECT_STREQ(idA.c_str(), ExtensionAt(2)->id().c_str()); 304 } 305 306 IN_PROC_BROWSER_TEST_F(ExtensionToolbarModelTest, Uninstall) { 307 // Load two extensions with browser action. 308 base::FilePath extension_a_path(test_data_dir_.AppendASCII("api_test") 309 .AppendASCII("browser_action") 310 .AppendASCII("basics")); 311 ASSERT_TRUE(LoadExtension(extension_a_path)); 312 base::FilePath extension_b_path(test_data_dir_.AppendASCII("api_test") 313 .AppendASCII("browser_action") 314 .AppendASCII("popup")); 315 ASSERT_TRUE(LoadExtension(extension_b_path)); 316 317 // Verify we got what we came for. 318 const Extension* extensionA = ExtensionAt(0); 319 const Extension* extensionB = ExtensionAt(1); 320 std::string idA = extensionA->id(); 321 std::string idB = extensionB->id(); 322 EXPECT_STREQ("A browser action with no icon that makes the page red", 323 extensionA->name().c_str()); 324 EXPECT_STREQ("Popup tester", extensionB->name().c_str()); 325 326 // Order is now A, B. Make B first. 327 model_->MoveBrowserAction(extensionB, 0); 328 329 // Order is now B, A. Uninstall Extension B. 330 UninstallExtension(idB); 331 332 // List contains only A now. Validate that. 333 EXPECT_STREQ(idA.c_str(), ExtensionAt(0)->id().c_str()); 334 EXPECT_EQ(1u, model_->toolbar_items().size()); 335 336 // Load Extension B again. 337 ASSERT_TRUE(LoadExtension(extension_b_path)); 338 EXPECT_EQ(2u, model_->toolbar_items().size()); 339 340 // Make sure Extension B is _not_ first (should have been forgotten at 341 // uninstall time). 342 EXPECT_STREQ(idA.c_str(), ExtensionAt(0)->id().c_str()); 343 EXPECT_STREQ(idB.c_str(), ExtensionAt(1)->id().c_str()); 344 } 345 346 IN_PROC_BROWSER_TEST_F(ExtensionToolbarModelTest, ReorderOnPrefChange) { 347 // Load three extensions with browser action. 348 base::FilePath extension_a_path(test_data_dir_.AppendASCII("api_test") 349 .AppendASCII("browser_action") 350 .AppendASCII("basics")); 351 ASSERT_TRUE(LoadExtension(extension_a_path)); 352 base::FilePath extension_b_path(test_data_dir_.AppendASCII("api_test") 353 .AppendASCII("browser_action") 354 .AppendASCII("popup")); 355 ASSERT_TRUE(LoadExtension(extension_b_path)); 356 base::FilePath extension_c_path(test_data_dir_.AppendASCII("api_test") 357 .AppendASCII("browser_action") 358 .AppendASCII("remove_popup")); 359 ASSERT_TRUE(LoadExtension(extension_c_path)); 360 std::string id_a = ExtensionAt(0)->id(); 361 std::string id_b = ExtensionAt(1)->id(); 362 std::string id_c = ExtensionAt(2)->id(); 363 364 // Change value of toolbar preference. 365 extensions::ExtensionIdList new_order; 366 new_order.push_back(id_c); 367 new_order.push_back(id_b); 368 extensions::ExtensionPrefs::Get(browser()->profile())->SetToolbarOrder( 369 new_order); 370 371 // Verify order is changed. 372 EXPECT_EQ(id_c, ExtensionAt(0)->id()); 373 EXPECT_EQ(id_b, ExtensionAt(1)->id()); 374 EXPECT_EQ(id_a, ExtensionAt(2)->id()); 375 } 376