| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 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 <algorithm> | |
| 6 #include <iterator> | |
| 7 | |
| 8 #include "base/bind.h" | |
| 9 #include "base/callback.h" | |
| 10 #include "base/command_line.h" | |
| 11 #include "base/memory/scoped_ptr.h" | |
| 12 #include "base/string_util.h" | |
| 13 #include "base/stringprintf.h" | |
| 14 #include "base/threading/sequenced_worker_pool.h" | |
| 15 #include "base/utf_string_conversions.h" | |
| 16 #include "chrome/browser/favicon/favicon_service.h" | |
| 17 #include "chrome/browser/favicon/favicon_service_factory.h" | |
| 18 #include "chrome/browser/intents/default_web_intent_service.h" | |
| 19 #include "chrome/browser/profiles/profile.h" | |
| 20 #include "chrome/browser/ui/browser.h" | |
| 21 #include "chrome/browser/ui/browser_commands.h" | |
| 22 #include "chrome/browser/ui/intents/web_intent_picker.h" | |
| 23 #include "chrome/browser/ui/intents/web_intent_picker_controller.h" | |
| 24 #include "chrome/browser/ui/intents/web_intent_picker_model.h" | |
| 25 #include "chrome/browser/ui/intents/web_intent_picker_model_observer.h" | |
| 26 #include "chrome/browser/ui/tabs/tab_strip_model.h" | |
| 27 #include "chrome/browser/webdata/web_data_service.h" | |
| 28 #include "chrome/browser/webdata/web_data_service_factory.h" | |
| 29 #include "chrome/common/chrome_notification_types.h" | |
| 30 #include "chrome/common/chrome_switches.h" | |
| 31 #include "chrome/common/url_constants.h" | |
| 32 #include "chrome/test/base/in_process_browser_test.h" | |
| 33 #include "chrome/test/base/ui_test_utils.h" | |
| 34 #include "content/public/browser/browser_thread.h" | |
| 35 #include "content/public/browser/notification_service.h" | |
| 36 #include "content/public/browser/web_contents.h" | |
| 37 #include "content/public/browser/web_intents_dispatcher.h" | |
| 38 #include "content/public/test/test_utils.h" | |
| 39 #include "extensions/common/constants.h" | |
| 40 #include "net/base/escape.h" | |
| 41 #include "net/base/mock_host_resolver.h" | |
| 42 #include "net/url_request/test_url_fetcher_factory.h" | |
| 43 #include "testing/gtest/include/gtest/gtest.h" | |
| 44 #include "ui/gfx/image/image_unittest_util.h" | |
| 45 #include "ui/gfx/image/image_util.h" | |
| 46 #include "webkit/glue/web_intent_service_data.h" | |
| 47 | |
| 48 namespace { | |
| 49 | |
| 50 const string16 kAction1(ASCIIToUTF16("http://webintents.org/share")); | |
| 51 const string16 kAction2(ASCIIToUTF16("http://www.example.com/foobar")); | |
| 52 const string16 kType1(ASCIIToUTF16("image/png")); | |
| 53 const string16 kType2(ASCIIToUTF16("text/*")); | |
| 54 const GURL kServiceURL1("http://www.google.com"); | |
| 55 const GURL kServiceURL2("http://www.chromium.org"); | |
| 56 const char kDummyExtensionId[] = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"; | |
| 57 const char kCWSResponseEmpty[] = | |
| 58 "{\"kind\":\"chromewebstore#itemList\",\"total_items\":0,\"start_index\":0," | |
| 59 "\"items\":[]}"; | |
| 60 | |
| 61 const char kCWSResponseResultFormat[] = | |
| 62 "{\"kind\":\"chromewebstore#itemList\"," | |
| 63 "\"total_items\":1," | |
| 64 "\"start_index\":0," | |
| 65 "\"items\":[{" | |
| 66 "\"kind\":\"chromewebstore#item\"," | |
| 67 "\"id\":\"%s\"," | |
| 68 "\"type\":\"APPLICATION\"," | |
| 69 "\"num_ratings\":0," | |
| 70 "\"average_rating\":0.0," | |
| 71 "\"manifest\": \"{\\n" | |
| 72 "\\\"name\\\": \\\"Dummy Share\\\",\\n" | |
| 73 "\\\"version\\\": \\\"1.0.0.0\\\",\\n" | |
| 74 "\\\"intents\\\": {\\n" | |
| 75 "\\\"%s\\\" : {\\n" | |
| 76 "\\\"type\\\" : [\\\"%s\\\"],\\n" | |
| 77 "\\\"path\\\" : \\\"share.html\\\",\\n" | |
| 78 "\\\"title\\\" : \\\"Dummy share!\\\",\\n" | |
| 79 "\\\"disposition\\\": \\\"inline\\\"\\n" | |
| 80 "}\\n" | |
| 81 "}\\n" | |
| 82 "}\\n\"," | |
| 83 "\"family_safe\":true," | |
| 84 "\"icon_url\": \"%s\"}]}"; | |
| 85 | |
| 86 const char kCWSFakeIconURLFormat[] = "http://example.com/%s/icon.png"; | |
| 87 | |
| 88 class DummyURLFetcherFactory : public net::URLFetcherFactory { | |
| 89 public: | |
| 90 DummyURLFetcherFactory() {} | |
| 91 virtual ~DummyURLFetcherFactory() {} | |
| 92 | |
| 93 virtual net::URLFetcher* CreateURLFetcher( | |
| 94 int id, | |
| 95 const GURL& url, | |
| 96 net::URLFetcher::RequestType request_type, | |
| 97 net::URLFetcherDelegate* d) OVERRIDE { | |
| 98 return new net::TestURLFetcher(id, url, d); | |
| 99 } | |
| 100 }; | |
| 101 | |
| 102 } // namespace | |
| 103 | |
| 104 class WebIntentPickerMock : public WebIntentPicker, | |
| 105 public WebIntentPickerModelObserver { | |
| 106 public: | |
| 107 WebIntentPickerMock() | |
| 108 : num_installed_services_(0), | |
| 109 num_icons_changed_(0), | |
| 110 num_extension_icons_changed_(0), | |
| 111 num_extensions_installed_(0), | |
| 112 message_loop_started_(false), | |
| 113 pending_async_completed_(false), | |
| 114 num_inline_disposition_(0), | |
| 115 delegate_(NULL) { | |
| 116 } | |
| 117 | |
| 118 void MockClose() { | |
| 119 delegate_->OnClosing(); | |
| 120 } | |
| 121 | |
| 122 // WebIntentPicker implementation. | |
| 123 virtual void Close() OVERRIDE { StopWaiting(); } | |
| 124 virtual void SetActionString(const string16& action) OVERRIDE {} | |
| 125 virtual void OnExtensionInstallSuccess(const std::string& id) OVERRIDE { | |
| 126 num_extensions_installed_++; | |
| 127 } | |
| 128 virtual void OnExtensionInstallFailure(const std::string& id) OVERRIDE {} | |
| 129 virtual void OnInlineDispositionAutoResize(const gfx::Size& size) OVERRIDE {} | |
| 130 virtual void OnPendingAsyncCompleted() OVERRIDE { | |
| 131 StopWaiting(); | |
| 132 } | |
| 133 virtual void InvalidateDelegate() OVERRIDE { | |
| 134 delegate_ = NULL; | |
| 135 } | |
| 136 | |
| 137 // WebIntentPickerModelObserver implementation. | |
| 138 virtual void OnModelChanged(WebIntentPickerModel* model) OVERRIDE { | |
| 139 num_installed_services_ = | |
| 140 static_cast<int>(model->GetInstalledServiceCount()); | |
| 141 } | |
| 142 virtual void OnFaviconChanged( | |
| 143 WebIntentPickerModel* model, size_t index) OVERRIDE { | |
| 144 num_icons_changed_++; | |
| 145 } | |
| 146 virtual void OnExtensionIconChanged( | |
| 147 WebIntentPickerModel* model, const std::string& extension_id) OVERRIDE { | |
| 148 num_extension_icons_changed_++; | |
| 149 } | |
| 150 virtual void OnInlineDisposition( | |
| 151 const string16& title, const GURL& url) OVERRIDE { | |
| 152 num_inline_disposition_++; | |
| 153 } | |
| 154 | |
| 155 void Wait() { | |
| 156 if (!pending_async_completed_) { | |
| 157 message_loop_started_ = true; | |
| 158 content::RunMessageLoop(); | |
| 159 pending_async_completed_ = false; | |
| 160 } | |
| 161 } | |
| 162 | |
| 163 void StopWaiting() { | |
| 164 pending_async_completed_ = true; | |
| 165 if (message_loop_started_) { | |
| 166 message_loop_started_ = false; | |
| 167 MessageLoop::current()->Quit(); | |
| 168 } | |
| 169 } | |
| 170 | |
| 171 int num_installed_services_; | |
| 172 int num_icons_changed_; | |
| 173 int num_extension_icons_changed_; | |
| 174 int num_extensions_installed_; | |
| 175 bool message_loop_started_; | |
| 176 bool pending_async_completed_; | |
| 177 int num_inline_disposition_; | |
| 178 WebIntentPickerDelegate* delegate_; | |
| 179 }; | |
| 180 | |
| 181 class IntentsDispatcherMock : public content::WebIntentsDispatcher { | |
| 182 public: | |
| 183 explicit IntentsDispatcherMock(const webkit_glue::WebIntentData& intent) | |
| 184 : intent_(intent), | |
| 185 dispatched_(false), | |
| 186 replied_(false) {} | |
| 187 | |
| 188 virtual const webkit_glue::WebIntentData& GetIntent() OVERRIDE { | |
| 189 return intent_; | |
| 190 } | |
| 191 | |
| 192 virtual void DispatchIntent(content::WebContents* web_contents) OVERRIDE { | |
| 193 dispatched_ = true; | |
| 194 } | |
| 195 | |
| 196 virtual void ResetDispatch() OVERRIDE { | |
| 197 } | |
| 198 | |
| 199 virtual void SendReply(const webkit_glue::WebIntentReply& reply) OVERRIDE { | |
| 200 replied_ = true; | |
| 201 } | |
| 202 | |
| 203 virtual void RegisterReplyNotification( | |
| 204 const base::Callback<void(webkit_glue::WebIntentReplyType)>&) OVERRIDE { | |
| 205 } | |
| 206 | |
| 207 webkit_glue::WebIntentData intent_; | |
| 208 bool dispatched_; | |
| 209 bool replied_; | |
| 210 }; | |
| 211 | |
| 212 class WebIntentPickerControllerBrowserTest : public InProcessBrowserTest { | |
| 213 public: | |
| 214 WebIntentPickerControllerBrowserTest() {} | |
| 215 | |
| 216 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { | |
| 217 // We start the test server now instead of in | |
| 218 // SetUpInProcessBrowserTestFixture so that we can get its port number. | |
| 219 ASSERT_TRUE(test_server()->Start()); | |
| 220 | |
| 221 net::HostPortPair host_port = test_server()->host_port_pair(); | |
| 222 command_line->AppendSwitchASCII( | |
| 223 switches::kAppsGalleryDownloadURL, | |
| 224 base::StringPrintf( | |
| 225 "http://www.example.com:%d/files/extensions/intents/%%s.crx", | |
| 226 host_port.port())); | |
| 227 command_line->AppendSwitchASCII( | |
| 228 switches::kAppsGalleryInstallAutoConfirmForTests, "accept"); | |
| 229 } | |
| 230 | |
| 231 virtual void SetUpInProcessBrowserTestFixture() OVERRIDE { | |
| 232 host_resolver()->AddRule("www.example.com", "127.0.0.1"); | |
| 233 } | |
| 234 | |
| 235 content::WebContents* GetWindowDispositionTarget( | |
| 236 WebIntentPickerController* controller) { | |
| 237 return controller->window_disposition_source_; | |
| 238 } | |
| 239 | |
| 240 virtual void SetUpOnMainThread() OVERRIDE { | |
| 241 // The FakeURLFetcherFactory will return a NULL URLFetcher if a request is | |
| 242 // created for a URL it doesn't know and there is no default factory. | |
| 243 // Instead, use this dummy factory to infinitely delay the request. | |
| 244 default_url_fetcher_factory_.reset(new DummyURLFetcherFactory); | |
| 245 fake_url_fetcher_factory_.reset( | |
| 246 new net::FakeURLFetcherFactory(default_url_fetcher_factory_.get())); | |
| 247 | |
| 248 web_data_service_ = WebDataServiceFactory::GetForProfile( | |
| 249 GetBrowser()->profile(), Profile::EXPLICIT_ACCESS); | |
| 250 favicon_service_ = FaviconServiceFactory::GetForProfile( | |
| 251 GetBrowser()->profile(), Profile::EXPLICIT_ACCESS); | |
| 252 controller_ = WebIntentPickerController::FromWebContents( | |
| 253 GetBrowser()->tab_strip_model()->GetActiveWebContents()); | |
| 254 | |
| 255 SetupMockPicker(); | |
| 256 controller_->set_model_observer(&picker_); | |
| 257 picker_.delegate_ = controller_; | |
| 258 | |
| 259 CreateFakeIcon(); | |
| 260 } | |
| 261 | |
| 262 virtual void SetupMockPicker() { | |
| 263 controller_->set_picker(&picker_); | |
| 264 } | |
| 265 | |
| 266 virtual Browser* GetBrowser() { return browser(); } | |
| 267 | |
| 268 void AddWebIntentService(const string16& action, const GURL& service_url) { | |
| 269 webkit_glue::WebIntentServiceData service; | |
| 270 service.action = action; | |
| 271 service.type = kType1; | |
| 272 service.service_url = service_url; | |
| 273 web_data_service_->AddWebIntentService(service); | |
| 274 } | |
| 275 | |
| 276 void AddCWSExtensionServiceEmpty(const string16& action) { | |
| 277 GURL cws_query_url = CWSIntentsRegistry::BuildQueryURL(action, kType1); | |
| 278 fake_url_fetcher_factory_->SetFakeResponse(cws_query_url.spec(), | |
| 279 kCWSResponseEmpty, true); | |
| 280 } | |
| 281 | |
| 282 void AddCWSExtensionServiceWithResult(const std::string& extension_id, | |
| 283 const string16& action, | |
| 284 const string16& type) { | |
| 285 GURL cws_query_url = CWSIntentsRegistry::BuildQueryURL(action, type); | |
| 286 std::string icon_url; | |
| 287 std::string escaped_action = net::EscapePath(UTF16ToUTF8(action)); | |
| 288 base::SStringPrintf(&icon_url, kCWSFakeIconURLFormat, | |
| 289 escaped_action.c_str()); | |
| 290 | |
| 291 std::string response; | |
| 292 base::SStringPrintf(&response, kCWSResponseResultFormat, | |
| 293 extension_id.c_str(), | |
| 294 UTF16ToUTF8(action).c_str(), UTF16ToUTF8(type).c_str(), | |
| 295 icon_url.c_str()); | |
| 296 fake_url_fetcher_factory_->SetFakeResponse(cws_query_url.spec(), response, | |
| 297 true); | |
| 298 | |
| 299 fake_url_fetcher_factory_->SetFakeResponse(icon_url, icon_response_, | |
| 300 true); | |
| 301 } | |
| 302 | |
| 303 void SetDefaultService(const string16& action, | |
| 304 const std::string& url) { | |
| 305 DefaultWebIntentService default_service; | |
| 306 default_service.action = action; | |
| 307 default_service.type = kType1; | |
| 308 default_service.user_date = 1000000; | |
| 309 default_service.service_url = url; | |
| 310 web_data_service_->AddDefaultWebIntentService(default_service); | |
| 311 } | |
| 312 | |
| 313 void OnSendReturnMessage( | |
| 314 webkit_glue::WebIntentReplyType reply_type) { | |
| 315 controller_->OnSendReturnMessage(reply_type); | |
| 316 } | |
| 317 | |
| 318 void OnServiceChosen( | |
| 319 const GURL& url, | |
| 320 webkit_glue::WebIntentServiceData::Disposition disposition) { | |
| 321 controller_->OnServiceChosen(url, disposition, | |
| 322 WebIntentPickerDelegate::kEnableDefaults); | |
| 323 } | |
| 324 | |
| 325 void OnCancelled() { | |
| 326 controller_->OnUserCancelledPickerDialog(); | |
| 327 } | |
| 328 | |
| 329 void OnExtensionInstallRequested(const std::string& extension_id) { | |
| 330 controller_->OnExtensionInstallRequested(extension_id); | |
| 331 } | |
| 332 | |
| 333 extensions::WebstoreInstaller* GetWebstoreInstaller() const { | |
| 334 return controller_->webstore_installer_.get(); | |
| 335 } | |
| 336 | |
| 337 void CreateFakeIcon() { | |
| 338 gfx::Image image(gfx::test::CreateImage()); | |
| 339 scoped_refptr<base::RefCountedMemory> image_data = image.As1xPNGBytes(); | |
| 340 DCHECK(image_data->size()); | |
| 341 | |
| 342 std::copy(image_data->front(), image_data->front() + image_data->size(), | |
| 343 std::back_inserter(icon_response_)); | |
| 344 } | |
| 345 | |
| 346 void ClickLocationBarButton(content::WebContents* service_web_contents) { | |
| 347 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
| 348 WebIntentPickerController* service_controller = | |
| 349 WebIntentPickerController::FromWebContents(service_web_contents); | |
| 350 service_controller->LocationBarPickerButtonClicked(); | |
| 351 } | |
| 352 | |
| 353 void CloseCurrentTab() { | |
| 354 content::WindowedNotificationObserver tab_close_observer( | |
| 355 content::NOTIFICATION_WEB_CONTENTS_DESTROYED, | |
| 356 content::NotificationService::AllSources()); | |
| 357 chrome::CloseTab(browser()); | |
| 358 tab_close_observer.Wait(); | |
| 359 } | |
| 360 | |
| 361 WebIntentPickerMock picker_; | |
| 362 scoped_refptr<WebDataService> web_data_service_; | |
| 363 FaviconService* favicon_service_; | |
| 364 WebIntentPickerController* controller_; | |
| 365 scoped_ptr<DummyURLFetcherFactory> default_url_fetcher_factory_; | |
| 366 scoped_ptr<net::FakeURLFetcherFactory> fake_url_fetcher_factory_; | |
| 367 std::string icon_response_; | |
| 368 }; | |
| 369 | |
| 370 IN_PROC_BROWSER_TEST_F(WebIntentPickerControllerBrowserTest, ChooseService) { | |
| 371 AddWebIntentService(kAction1, kServiceURL1); | |
| 372 AddWebIntentService(kAction1, kServiceURL2); | |
| 373 AddCWSExtensionServiceEmpty(kAction1); | |
| 374 | |
| 375 webkit_glue::WebIntentData intent; | |
| 376 intent.action = kAction1; | |
| 377 intent.type = kType1; | |
| 378 IntentsDispatcherMock dispatcher(intent); | |
| 379 controller_->SetIntentsDispatcher(&dispatcher); | |
| 380 | |
| 381 controller_->ShowDialog(kAction1, kType1); | |
| 382 picker_.Wait(); | |
| 383 EXPECT_EQ(2, picker_.num_installed_services_); | |
| 384 EXPECT_EQ(0, picker_.num_icons_changed_); | |
| 385 | |
| 386 TabStripModel* tab_strip = browser()->tab_strip_model(); | |
| 387 OnServiceChosen(kServiceURL2, | |
| 388 webkit_glue::WebIntentServiceData::DISPOSITION_WINDOW); | |
| 389 ASSERT_EQ(2, tab_strip->count()); | |
| 390 EXPECT_EQ(GURL(kServiceURL2), | |
| 391 tab_strip->GetActiveWebContents()->GetURL()); | |
| 392 | |
| 393 EXPECT_TRUE(GetWindowDispositionTarget( | |
| 394 WebIntentPickerController::FromWebContents( | |
| 395 tab_strip->GetActiveWebContents()))); | |
| 396 | |
| 397 EXPECT_TRUE(dispatcher.dispatched_); | |
| 398 | |
| 399 OnSendReturnMessage(webkit_glue::WEB_INTENT_REPLY_SUCCESS); | |
| 400 ASSERT_EQ(1, tab_strip->count()); | |
| 401 } | |
| 402 | |
| 403 IN_PROC_BROWSER_TEST_F(WebIntentPickerControllerBrowserTest, | |
| 404 FetchExtensionIcon) { | |
| 405 AddWebIntentService(kAction1, kServiceURL1); | |
| 406 AddWebIntentService(kAction1, kServiceURL2); | |
| 407 AddCWSExtensionServiceWithResult(kDummyExtensionId, kAction1, kType1); | |
| 408 | |
| 409 webkit_glue::WebIntentData intent; | |
| 410 intent.action = kAction1; | |
| 411 intent.type = kType1; | |
| 412 IntentsDispatcherMock dispatcher(intent); | |
| 413 controller_->SetIntentsDispatcher(&dispatcher); | |
| 414 | |
| 415 controller_->ShowDialog(kAction1, kType1); | |
| 416 picker_.Wait(); | |
| 417 // Flush all pending worker tasks for PNG decoding. | |
| 418 content::BrowserThread::GetBlockingPool()->FlushForTesting(); | |
| 419 // Flush all tasks posted from the worker tasks. | |
| 420 MessageLoop::current()->RunUntilIdle(); | |
| 421 EXPECT_EQ(2, picker_.num_installed_services_); | |
| 422 EXPECT_EQ(0, picker_.num_icons_changed_); | |
| 423 EXPECT_EQ(1, picker_.num_extension_icons_changed_); | |
| 424 } | |
| 425 | |
| 426 IN_PROC_BROWSER_TEST_F(WebIntentPickerControllerBrowserTest, OpenCancelOpen) { | |
| 427 AddWebIntentService(kAction1, kServiceURL1); | |
| 428 AddWebIntentService(kAction1, kServiceURL2); | |
| 429 AddCWSExtensionServiceEmpty(kAction1); | |
| 430 | |
| 431 webkit_glue::WebIntentData intent; | |
| 432 intent.action = kAction1; | |
| 433 intent.type = kType1; | |
| 434 IntentsDispatcherMock dispatcher(intent); | |
| 435 controller_->SetIntentsDispatcher(&dispatcher); | |
| 436 | |
| 437 controller_->ShowDialog(kAction1, kType1); | |
| 438 picker_.Wait(); | |
| 439 OnCancelled(); | |
| 440 | |
| 441 controller_->ShowDialog(kAction1, kType1); | |
| 442 OnCancelled(); | |
| 443 } | |
| 444 | |
| 445 IN_PROC_BROWSER_TEST_F(WebIntentPickerControllerBrowserTest, | |
| 446 CloseTargetTabReturnToSource) { | |
| 447 AddWebIntentService(kAction1, kServiceURL1); | |
| 448 AddCWSExtensionServiceEmpty(kAction1); | |
| 449 | |
| 450 TabStripModel* tab_strip = browser()->tab_strip_model(); | |
| 451 GURL original = tab_strip->GetActiveWebContents()->GetURL(); | |
| 452 | |
| 453 // Open a new page, but keep focus on original. | |
| 454 ui_test_utils::NavigateToURLWithDisposition( | |
| 455 browser(), GURL(chrome::kChromeUINewTabURL), NEW_BACKGROUND_TAB, | |
| 456 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION); | |
| 457 ASSERT_EQ(2, tab_strip->count()); | |
| 458 EXPECT_EQ(original, tab_strip->GetActiveWebContents()->GetURL()); | |
| 459 | |
| 460 webkit_glue::WebIntentData intent; | |
| 461 intent.action = kAction1; | |
| 462 intent.type = kType1; | |
| 463 IntentsDispatcherMock dispatcher(intent); | |
| 464 controller_->SetIntentsDispatcher(&dispatcher); | |
| 465 | |
| 466 controller_->ShowDialog(kAction1, kType1); | |
| 467 picker_.Wait(); | |
| 468 EXPECT_EQ(1, picker_.num_installed_services_); | |
| 469 | |
| 470 OnServiceChosen(kServiceURL1, | |
| 471 webkit_glue::WebIntentServiceData::DISPOSITION_WINDOW); | |
| 472 ASSERT_EQ(3, tab_strip->count()); | |
| 473 EXPECT_EQ(GURL(kServiceURL1), | |
| 474 tab_strip->GetActiveWebContents()->GetURL()); | |
| 475 | |
| 476 EXPECT_TRUE(dispatcher.dispatched_); | |
| 477 | |
| 478 OnSendReturnMessage(webkit_glue::WEB_INTENT_REPLY_SUCCESS); | |
| 479 ASSERT_EQ(2, tab_strip->count()); | |
| 480 EXPECT_EQ(original, tab_strip->GetActiveWebContents()->GetURL()); | |
| 481 | |
| 482 CloseCurrentTab(); | |
| 483 } | |
| 484 | |
| 485 class WebIntentPickerControllerIncognitoBrowserTest | |
| 486 : public WebIntentPickerControllerBrowserTest { | |
| 487 public: | |
| 488 WebIntentPickerControllerIncognitoBrowserTest() {} | |
| 489 | |
| 490 virtual void SetUpOnMainThread() OVERRIDE { | |
| 491 incognito_browser_ = CreateIncognitoBrowser(); | |
| 492 WebIntentPickerControllerBrowserTest::SetUpOnMainThread(); | |
| 493 } | |
| 494 | |
| 495 virtual Browser* GetBrowser() OVERRIDE { return incognito_browser_; } | |
| 496 | |
| 497 int pending_async_count() { return controller_->pending_async_count_; } | |
| 498 | |
| 499 private: | |
| 500 Browser* incognito_browser_; | |
| 501 }; | |
| 502 | |
| 503 IN_PROC_BROWSER_TEST_F(WebIntentPickerControllerIncognitoBrowserTest, | |
| 504 ShowDialogShouldntCrash) { | |
| 505 webkit_glue::WebIntentData intent; | |
| 506 intent.action = kAction1; | |
| 507 intent.type = kType1; | |
| 508 IntentsDispatcherMock dispatcher(intent); | |
| 509 controller_->SetIntentsDispatcher(&dispatcher); | |
| 510 | |
| 511 controller_->ShowDialog(kAction1, kType1); | |
| 512 // This should do nothing for now. | |
| 513 EXPECT_EQ(0, pending_async_count()); | |
| 514 } | |
| 515 | |
| 516 IN_PROC_BROWSER_TEST_F(WebIntentPickerControllerBrowserTest, | |
| 517 ExtensionInstallSuccess) { | |
| 518 const char extension_id[] = "ooodacpbmglpoagccnepcbfhfhpdgddn"; | |
| 519 AddCWSExtensionServiceWithResult(extension_id, kAction1, kType2); | |
| 520 | |
| 521 webkit_glue::WebIntentData intent; | |
| 522 intent.action = kAction1; | |
| 523 intent.type = kType2; | |
| 524 IntentsDispatcherMock dispatcher(intent); | |
| 525 controller_->SetIntentsDispatcher(&dispatcher); | |
| 526 | |
| 527 controller_->ShowDialog(kAction1, kType2); | |
| 528 picker_.Wait(); | |
| 529 | |
| 530 TabStripModel* tab_strip = browser()->tab_strip_model(); | |
| 531 ASSERT_EQ(1, tab_strip->count()); | |
| 532 OnExtensionInstallRequested(extension_id); | |
| 533 picker_.Wait(); | |
| 534 EXPECT_EQ(1, picker_.num_extensions_installed_); | |
| 535 const extensions::Extension* extension = browser()->profile()-> | |
| 536 GetExtensionService()->GetExtensionById(extension_id, false); | |
| 537 EXPECT_TRUE(extension); | |
| 538 | |
| 539 // Installing an extension should also choose it. Since this extension uses | |
| 540 // window disposition, it will create a new tab. | |
| 541 EXPECT_EQ(2, tab_strip->count()); | |
| 542 EXPECT_EQ(0, picker_.num_inline_disposition_); | |
| 543 | |
| 544 CloseCurrentTab(); | |
| 545 } | |
| 546 | |
| 547 // Tests that inline install of an extension using inline disposition works | |
| 548 // and brings up content as inline content. | |
| 549 IN_PROC_BROWSER_TEST_F(WebIntentPickerControllerBrowserTest, | |
| 550 ExtensionInstallSuccessInline) { | |
| 551 const char extension_id[] = "nnhendkbgefomfgdlnmfhhmihihlljpi"; | |
| 552 AddCWSExtensionServiceWithResult(extension_id, kAction1, kType2); | |
| 553 | |
| 554 webkit_glue::WebIntentData intent; | |
| 555 intent.action = kAction1; | |
| 556 intent.type = kType2; | |
| 557 IntentsDispatcherMock dispatcher(intent); | |
| 558 controller_->SetIntentsDispatcher(&dispatcher); | |
| 559 | |
| 560 controller_->ShowDialog(kAction1, kType2); | |
| 561 picker_.Wait(); | |
| 562 | |
| 563 OnExtensionInstallRequested(extension_id); | |
| 564 picker_.Wait(); | |
| 565 EXPECT_EQ(1, picker_.num_extensions_installed_); | |
| 566 const extensions::Extension* extension = browser()->profile()-> | |
| 567 GetExtensionService()->GetExtensionById(extension_id, false); | |
| 568 EXPECT_TRUE(extension); | |
| 569 | |
| 570 // Installing an extension should also choose it. Since this extension uses | |
| 571 // inline disposition, it will create no tabs and invoke OnInlineDisposition. | |
| 572 TabStripModel* tab_strip = browser()->tab_strip_model(); | |
| 573 EXPECT_EQ(1, tab_strip->count()); | |
| 574 EXPECT_EQ(1, picker_.num_inline_disposition_); | |
| 575 } | |
| 576 | |
| 577 IN_PROC_BROWSER_TEST_F(WebIntentPickerControllerBrowserTest, | |
| 578 WebstoreInstallerLifetime) { | |
| 579 const char extension_id[] = "nnhendkbgefomfgdlnmfhhmihihlljpi"; | |
| 580 AddCWSExtensionServiceWithResult(extension_id, kAction1, kType2); | |
| 581 | |
| 582 webkit_glue::WebIntentData intent; | |
| 583 intent.action = kAction1; | |
| 584 intent.type = kType2; | |
| 585 IntentsDispatcherMock dispatcher(intent); | |
| 586 controller_->SetIntentsDispatcher(&dispatcher); | |
| 587 | |
| 588 controller_->ShowDialog(kAction1, kType2); | |
| 589 picker_.Wait(); | |
| 590 | |
| 591 // We haven't yet created a WebstoreInstaller. | |
| 592 EXPECT_FALSE(GetWebstoreInstaller()); | |
| 593 | |
| 594 // While extension install is pending, we have a WebstoreInstaller. | |
| 595 OnExtensionInstallRequested(extension_id); | |
| 596 EXPECT_TRUE(GetWebstoreInstaller()); | |
| 597 | |
| 598 // After extension install the WebstoreInstaller is cleaned up. | |
| 599 picker_.Wait(); | |
| 600 EXPECT_EQ(1, picker_.num_extensions_installed_); | |
| 601 EXPECT_FALSE(GetWebstoreInstaller()); | |
| 602 } | |
| 603 | |
| 604 // Test that an explicit intent does not trigger loading intents from the | |
| 605 // registry (skips the picker), and creates the intent service handler | |
| 606 // immediately. | |
| 607 IN_PROC_BROWSER_TEST_F(WebIntentPickerControllerBrowserTest, | |
| 608 ExplicitIntentTest) { | |
| 609 // Install a target service for the explicit intent. | |
| 610 const char extension_id[] = "ooodacpbmglpoagccnepcbfhfhpdgddn"; | |
| 611 AddCWSExtensionServiceWithResult(extension_id, kAction1, kType2); | |
| 612 | |
| 613 webkit_glue::WebIntentData intent; | |
| 614 intent.action = kAction1; | |
| 615 intent.type = kType2; | |
| 616 IntentsDispatcherMock dispatcher(intent); | |
| 617 controller_->SetIntentsDispatcher(&dispatcher); | |
| 618 | |
| 619 controller_->ShowDialog(kAction1, kType2); | |
| 620 picker_.Wait(); | |
| 621 | |
| 622 TabStripModel* tab_strip = browser()->tab_strip_model(); | |
| 623 OnExtensionInstallRequested(extension_id); | |
| 624 picker_.Wait(); | |
| 625 ASSERT_EQ(1, picker_.num_extensions_installed_); | |
| 626 // The intent launches a new tab. | |
| 627 ASSERT_EQ(2, tab_strip->count()); | |
| 628 | |
| 629 // Make the controller think nothing is being shown. | |
| 630 picker_.MockClose(); | |
| 631 SetupMockPicker(); | |
| 632 | |
| 633 // Now call the explicit intent. | |
| 634 webkit_glue::WebIntentData explicitIntent; | |
| 635 explicitIntent.action = kAction1; | |
| 636 explicitIntent.type = kType2; | |
| 637 explicitIntent.service = GURL(StringPrintf("%s://%s/%s", | |
| 638 extensions::kExtensionScheme, | |
| 639 extension_id, | |
| 640 "share.html")); | |
| 641 IntentsDispatcherMock dispatcher2(explicitIntent); | |
| 642 controller_->SetIntentsDispatcher(&dispatcher2); | |
| 643 ui_test_utils::WindowedTabAddedNotificationObserver new_tab_observer(( | |
| 644 content::Source<content::WebContentsDelegate>(browser()))); | |
| 645 controller_->ShowDialog(kAction1, kType2); | |
| 646 new_tab_observer.Wait(); | |
| 647 | |
| 648 content::WebContents* service_web_contents = new_tab_observer.GetTab(); | |
| 649 DCHECK(service_web_contents); | |
| 650 | |
| 651 // Location bar button should not be shown for explicit intents. | |
| 652 WebIntentPickerController* service_controller = | |
| 653 WebIntentPickerController::FromWebContents(service_web_contents); | |
| 654 DCHECK(service_controller); | |
| 655 EXPECT_FALSE(service_controller->ShowLocationBarPickerButton()); | |
| 656 | |
| 657 EXPECT_EQ(3, tab_strip->count()); | |
| 658 EXPECT_EQ(0, picker_.num_inline_disposition_); | |
| 659 EXPECT_FALSE(dispatcher2.replied_); | |
| 660 | |
| 661 // num_installed_services_ would be 2 if the intent wasn't explicit. | |
| 662 EXPECT_EQ(1, picker_.num_installed_services_); | |
| 663 | |
| 664 // Close tabs to get rid of them before the dispatchers go out of scope at the | |
| 665 // end of this method. | |
| 666 CloseCurrentTab(); | |
| 667 CloseCurrentTab(); | |
| 668 } | |
| 669 | |
| 670 // Test that an explicit intent for non-installed extension won't | |
| 671 // complete. | |
| 672 IN_PROC_BROWSER_TEST_F(WebIntentPickerControllerBrowserTest, | |
| 673 ExplicitIntentNoExtensionTest) { | |
| 674 AddWebIntentService(kAction1, kServiceURL1); | |
| 675 AddWebIntentService(kAction1, kServiceURL2); | |
| 676 AddCWSExtensionServiceWithResult(kDummyExtensionId, kAction1, kType1); | |
| 677 | |
| 678 webkit_glue::WebIntentData intent; | |
| 679 intent.action = kAction1; | |
| 680 intent.type = kType1; | |
| 681 intent.service = GURL(StringPrintf("%s://%s/%s", | |
| 682 extensions::kExtensionScheme, | |
| 683 kDummyExtensionId, | |
| 684 UTF16ToASCII(kAction1).c_str())); | |
| 685 IntentsDispatcherMock dispatcher(intent); | |
| 686 controller_->SetIntentsDispatcher(&dispatcher); | |
| 687 controller_->ShowDialog(kAction1, kType1); | |
| 688 picker_.Wait(); | |
| 689 | |
| 690 TabStripModel* tab_strip = browser()->tab_strip_model(); | |
| 691 EXPECT_EQ(1, tab_strip->count()); | |
| 692 EXPECT_EQ(0, picker_.num_inline_disposition_); | |
| 693 EXPECT_TRUE(dispatcher.replied_); | |
| 694 | |
| 695 // num_installed_services_ would be 2 if the intent wasn't explicit. | |
| 696 EXPECT_EQ(0, picker_.num_installed_services_); | |
| 697 } | |
| 698 | |
| 699 // Test that explicit intents won't load uninstalled non-extensions. | |
| 700 IN_PROC_BROWSER_TEST_F(WebIntentPickerControllerBrowserTest, | |
| 701 ExplicitIntentNonExtensionTest) { | |
| 702 AddWebIntentService(kAction1, kServiceURL1); | |
| 703 AddWebIntentService(kAction1, kServiceURL2); | |
| 704 AddCWSExtensionServiceWithResult(kDummyExtensionId, kAction1, kType1); | |
| 705 | |
| 706 webkit_glue::WebIntentData intent; | |
| 707 intent.action = kAction1; | |
| 708 intent.type = kType1; | |
| 709 intent.service = GURL("http://www.uninstalled.com/"); | |
| 710 IntentsDispatcherMock dispatcher(intent); | |
| 711 controller_->SetIntentsDispatcher(&dispatcher); | |
| 712 controller_->ShowDialog(kAction1, kType1); | |
| 713 picker_.Wait(); | |
| 714 | |
| 715 TabStripModel* tab_strip = browser()->tab_strip_model(); | |
| 716 EXPECT_EQ(1, tab_strip->count()); | |
| 717 EXPECT_EQ(0, picker_.num_inline_disposition_); | |
| 718 | |
| 719 // num_installed_services_ would be 2 if the intent wasn't explicit. | |
| 720 EXPECT_EQ(0, picker_.num_installed_services_); | |
| 721 EXPECT_TRUE(dispatcher.replied_); | |
| 722 } | |
| 723 | |
| 724 IN_PROC_BROWSER_TEST_F(WebIntentPickerControllerBrowserTest, | |
| 725 DefaultsTest) { | |
| 726 AddWebIntentService(kAction1, kServiceURL1); | |
| 727 AddWebIntentService(kAction1, kServiceURL2); | |
| 728 AddCWSExtensionServiceEmpty(kAction1); | |
| 729 | |
| 730 SetDefaultService(kAction1, kServiceURL1.spec()); | |
| 731 | |
| 732 webkit_glue::WebIntentData intent; | |
| 733 intent.action = kAction1; | |
| 734 intent.type = kType1; | |
| 735 IntentsDispatcherMock dispatcher(intent); | |
| 736 controller_->SetIntentsDispatcher(&dispatcher); | |
| 737 | |
| 738 ui_test_utils::WindowedTabAddedNotificationObserver new_tab_observer(( | |
| 739 content::Source<content::WebContentsDelegate>(browser()))); | |
| 740 controller_->ShowDialog(kAction1, kType1); | |
| 741 new_tab_observer.Wait(); | |
| 742 WebIntentPickerController* service_controller = | |
| 743 WebIntentPickerController::FromWebContents(new_tab_observer.GetTab()); | |
| 744 EXPECT_TRUE(service_controller->ShowLocationBarPickerButton()); | |
| 745 | |
| 746 EXPECT_EQ(2, picker_.num_installed_services_); | |
| 747 | |
| 748 // The tab is shown immediately without needing to call OnServiceChosen. | |
| 749 TabStripModel* tab_strip = browser()->tab_strip_model(); | |
| 750 ASSERT_EQ(2, tab_strip->count()); | |
| 751 EXPECT_EQ(GURL(kServiceURL1), | |
| 752 tab_strip->GetActiveWebContents()->GetURL()); | |
| 753 | |
| 754 EXPECT_TRUE(dispatcher.dispatched_); | |
| 755 | |
| 756 CloseCurrentTab(); | |
| 757 } | |
| 758 | |
| 759 IN_PROC_BROWSER_TEST_F(WebIntentPickerControllerBrowserTest, | |
| 760 ChooseAnotherService) { | |
| 761 AddWebIntentService(kAction1, kServiceURL1); | |
| 762 AddWebIntentService(kAction1, kServiceURL2); | |
| 763 AddCWSExtensionServiceEmpty(kAction1); | |
| 764 | |
| 765 // Bring up the picker to get the test-installed services so we can create a | |
| 766 // default with the right defaulting fingerprint. | |
| 767 SetDefaultService(kAction1, kServiceURL1.spec()); | |
| 768 | |
| 769 webkit_glue::WebIntentData intent; | |
| 770 intent.action = kAction1; | |
| 771 intent.type = kType1; | |
| 772 IntentsDispatcherMock dispatcher(intent); | |
| 773 controller_->SetIntentsDispatcher(&dispatcher); | |
| 774 | |
| 775 ui_test_utils::WindowedTabAddedNotificationObserver new_tab_observer(( | |
| 776 content::Source<content::WebContentsDelegate>(browser()))); | |
| 777 controller_->ShowDialog(kAction1, kType1); | |
| 778 new_tab_observer.Wait(); | |
| 779 content::WebContents* service_web_contents = new_tab_observer.GetTab(); | |
| 780 | |
| 781 EXPECT_EQ(2, picker_.num_installed_services_); | |
| 782 | |
| 783 // The tab is shown immediately without needing to call OnServiceChosen. | |
| 784 TabStripModel* tab_strip = browser()->tab_strip_model(); | |
| 785 ASSERT_EQ(2, tab_strip->count()); | |
| 786 EXPECT_EQ(GURL(kServiceURL1), | |
| 787 tab_strip->GetActiveWebContents()->GetURL()); | |
| 788 | |
| 789 // Simulate click on the location bar use-another-service button. | |
| 790 content::WindowedNotificationObserver observer( | |
| 791 chrome::NOTIFICATION_TAB_CLOSING, | |
| 792 content::NotificationService::AllSources()); | |
| 793 content::BrowserThread::PostTask( | |
| 794 content::BrowserThread::UI, FROM_HERE, | |
| 795 base::Bind(&WebIntentPickerControllerBrowserTest::ClickLocationBarButton, | |
| 796 base::Unretained(this), | |
| 797 service_web_contents)); | |
| 798 observer.Wait(); | |
| 799 picker_.Wait(); | |
| 800 | |
| 801 // The service tab is closed and the picker is shown again | |
| 802 // on the original tab. | |
| 803 EXPECT_EQ(1, tab_strip->count()); | |
| 804 EXPECT_EQ(2, picker_.num_installed_services_); | |
| 805 EXPECT_EQ(0, picker_.num_inline_disposition_); | |
| 806 } | |
| OLD | NEW |