Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <string> | 5 #include <string> |
| 6 | 6 |
| 7 #include "base/macros.h" | |
| 7 #include "base/memory/scoped_ptr.h" | 8 #include "base/memory/scoped_ptr.h" |
| 8 #include "base/strings/string16.h" | 9 #include "base/strings/string16.h" |
| 9 #include "base/strings/utf_string_conversions.h" | 10 #include "base/strings/utf_string_conversions.h" |
| 10 #include "chrome/app/chrome_command_ids.h" | 11 #include "chrome/app/chrome_command_ids.h" |
| 11 #include "chrome/browser/chrome_notification_types.h" | 12 #include "chrome/browser/chrome_notification_types.h" |
| 12 #include "chrome/browser/renderer_context_menu/render_view_context_menu.h" | 13 #include "chrome/browser/renderer_context_menu/render_view_context_menu.h" |
| 13 #include "chrome/browser/renderer_context_menu/render_view_context_menu_browsert est_util.h" | 14 #include "chrome/browser/renderer_context_menu/render_view_context_menu_browsert est_util.h" |
| 14 #include "chrome/browser/renderer_context_menu/render_view_context_menu_test_uti l.h" | 15 #include "chrome/browser/renderer_context_menu/render_view_context_menu_test_uti l.h" |
| 16 #include "chrome/browser/search_engines/template_url_service_factory.h" | |
| 15 #include "chrome/browser/ui/browser.h" | 17 #include "chrome/browser/ui/browser.h" |
| 16 #include "chrome/browser/ui/tabs/tab_strip_model.h" | 18 #include "chrome/browser/ui/tabs/tab_strip_model.h" |
| 19 #include "chrome/common/render_messages.h" | |
| 17 #include "chrome/test/base/in_process_browser_test.h" | 20 #include "chrome/test/base/in_process_browser_test.h" |
| 18 #include "chrome/test/base/ui_test_utils.h" | 21 #include "chrome/test/base/ui_test_utils.h" |
| 22 #include "components/search_engines/template_url_data.h" | |
| 23 #include "components/search_engines/template_url_service.h" | |
| 24 #include "content/public/browser/browser_message_filter.h" | |
| 25 #include "content/public/browser/browser_thread.h" | |
| 19 #include "content/public/browser/navigation_controller.h" | 26 #include "content/public/browser/navigation_controller.h" |
| 20 #include "content/public/browser/navigation_entry.h" | 27 #include "content/public/browser/navigation_entry.h" |
| 21 #include "content/public/browser/notification_service.h" | 28 #include "content/public/browser/notification_service.h" |
| 29 #include "content/public/browser/render_process_host.h" | |
| 22 #include "content/public/browser/render_view_host.h" | 30 #include "content/public/browser/render_view_host.h" |
| 23 #include "content/public/browser/web_contents.h" | 31 #include "content/public/browser/web_contents.h" |
| 24 #include "content/public/test/browser_test_utils.h" | 32 #include "content/public/test/browser_test_utils.h" |
| 33 #include "content/public/test/test_utils.h" | |
| 25 #include "third_party/WebKit/public/web/WebContextMenuData.h" | 34 #include "third_party/WebKit/public/web/WebContextMenuData.h" |
| 26 #include "third_party/WebKit/public/web/WebInputEvent.h" | 35 #include "third_party/WebKit/public/web/WebInputEvent.h" |
| 27 | 36 |
| 28 using content::WebContents; | 37 using content::WebContents; |
| 29 | 38 |
| 30 namespace { | 39 namespace { |
| 31 | 40 |
| 32 class ContextMenuBrowserTest : public InProcessBrowserTest { | 41 class ContextMenuBrowserTest : public InProcessBrowserTest { |
| 33 public: | 42 public: |
| 34 ContextMenuBrowserTest() { } | 43 ContextMenuBrowserTest() { } |
| (...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 281 TestRenderViewContextMenu menu(tab->GetMainFrame(), context_menu_params); | 290 TestRenderViewContextMenu menu(tab->GetMainFrame(), context_menu_params); |
| 282 menu.Init(); | 291 menu.Init(); |
| 283 | 292 |
| 284 // The item shouldn't be enabled in the menu. | 293 // The item shouldn't be enabled in the menu. |
| 285 EXPECT_FALSE(menu.IsCommandIdEnabled(IDC_CONTENT_CONTEXT_VIEWPAGEINFO)); | 294 EXPECT_FALSE(menu.IsCommandIdEnabled(IDC_CONTENT_CONTEXT_VIEWPAGEINFO)); |
| 286 | 295 |
| 287 // Ensure that viewing page info doesn't crash even if you can get to it. | 296 // Ensure that viewing page info doesn't crash even if you can get to it. |
| 288 menu.ExecuteCommand(IDC_CONTENT_CONTEXT_VIEWPAGEINFO, 0); | 297 menu.ExecuteCommand(IDC_CONTENT_CONTEXT_VIEWPAGEINFO, 0); |
| 289 } | 298 } |
| 290 | 299 |
| 300 class ThumbnailResponseWatcher : public content::NotificationObserver { | |
| 301 public: | |
| 302 enum QuitReason { | |
| 303 STILL_RUNNING = 0, | |
| 304 THUMBNAIL_RECEIVED, | |
| 305 RENDER_PROCESS_GONE, | |
| 306 }; | |
| 307 | |
| 308 class MessageFilter : public content::BrowserMessageFilter { | |
| 309 public: | |
| 310 explicit MessageFilter(ThumbnailResponseWatcher* owner) | |
| 311 : content::BrowserMessageFilter(ChromeMsgStart), owner_(owner) {} | |
| 312 | |
| 313 bool OnMessageReceived(const IPC::Message& message) override { | |
| 314 if (message.type() == | |
| 315 ChromeViewHostMsg_RequestThumbnailForContextNode_ACK::ID) { | |
| 316 content::BrowserThread::PostTask( | |
| 317 content::BrowserThread::UI, FROM_HERE, | |
| 318 base::Bind(&MessageFilter::OnRequestThumbnailForContextNodeACK, | |
| 319 this)); | |
| 320 } | |
| 321 return false; | |
| 322 } | |
| 323 | |
| 324 void OnRequestThumbnailForContextNodeACK() { | |
| 325 if (owner_) | |
| 326 owner_->OnRequestThumbnailForContextNodeACK(); | |
| 327 } | |
| 328 | |
| 329 void Disown() { owner_ = nullptr; } | |
| 330 | |
| 331 private: | |
| 332 ~MessageFilter() override {} | |
| 333 | |
| 334 ThumbnailResponseWatcher* owner_; | |
| 335 | |
| 336 DISALLOW_COPY_AND_ASSIGN(MessageFilter); | |
| 337 }; | |
| 338 | |
| 339 explicit ThumbnailResponseWatcher( | |
| 340 content::RenderProcessHost* render_process_host) | |
| 341 : message_loop_runner_(new content::MessageLoopRunner), | |
| 342 filter_(new MessageFilter(this)), | |
| 343 quit_reason_(STILL_RUNNING) { | |
| 344 notification_registrar_.Add( | |
| 345 this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED, | |
| 346 content::Source<content::RenderProcessHost>(render_process_host)); | |
| 347 notification_registrar_.Add( | |
| 348 this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, | |
| 349 content::Source<content::RenderProcessHost>(render_process_host)); | |
| 350 render_process_host->AddFilter(filter_.get()); | |
| 351 } | |
| 352 | |
| 353 ~ThumbnailResponseWatcher() override { filter_->Disown(); } | |
| 354 | |
| 355 QuitReason Wait() WARN_UNUSED_RESULT { | |
| 356 message_loop_runner_->Run(); | |
| 357 DCHECK_NE(quit_reason_, STILL_RUNNING); | |
|
Peter Kasting
2014/12/12 00:35:51
Nit: (expected, actual)
jbroman
2014/12/12 01:10:46
Done.
| |
| 358 return quit_reason_; | |
| 359 } | |
| 360 | |
| 361 void Observe(int type, | |
| 362 const content::NotificationSource& source, | |
| 363 const content::NotificationDetails& details) override { | |
| 364 DCHECK(type == content::NOTIFICATION_RENDERER_PROCESS_CLOSED || | |
| 365 type == content::NOTIFICATION_RENDERER_PROCESS_TERMINATED); | |
| 366 quit_reason_ = RENDER_PROCESS_GONE; | |
| 367 message_loop_runner_->Quit(); | |
| 368 } | |
| 369 | |
| 370 void OnRequestThumbnailForContextNodeACK() { | |
| 371 quit_reason_ = THUMBNAIL_RECEIVED; | |
| 372 message_loop_runner_->Quit(); | |
| 373 } | |
| 374 | |
| 375 private: | |
| 376 scoped_refptr<content::MessageLoopRunner> message_loop_runner_; | |
| 377 scoped_refptr<MessageFilter> filter_; | |
| 378 content::NotificationRegistrar notification_registrar_; | |
| 379 QuitReason quit_reason_; | |
| 380 | |
| 381 DISALLOW_COPY_AND_ASSIGN(ThumbnailResponseWatcher); | |
| 382 }; | |
| 383 | |
| 384 // Maintains image search test state. In particular, note that |menu_observer_| | |
| 385 // must live until the right-click completes asynchronously. | |
| 386 class ImageSearchTestHelper { | |
| 387 public: | |
|
Peter Kasting
2014/12/12 00:35:51
Nit: I think all these can be protected
jbroman
2014/12/12 01:10:46
If this actually were a fixture class (which raise
Peter Kasting
2014/12/12 01:14:45
Oh duh, somehow I failed to process your comments
jbroman
2014/12/12 01:58:24
Done. It still needs the filename argument (and yo
| |
| 388 static const char kImageSearchURL[]; | |
| 389 | |
| 390 ImageSearchTestHelper(net::SpawnedTestServer* test_server, Browser* browser) | |
| 391 : menu_observer_(IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE), | |
| 392 test_server_(test_server), | |
| 393 browser_(browser) {} | |
| 394 | |
| 395 void SetupAndLoadImagePage(const std::string& image_path) { | |
| 396 // The test server must start first, so that we know the port that the test | |
| 397 // server is using. | |
| 398 ASSERT_TRUE(test_server_->Start()); | |
| 399 SetupImageSearchEngine(); | |
| 400 | |
| 401 // Go to a page with an image in it. The test server doesn't serve the image | |
| 402 // with the right MIME type, so use a data URL to make a page containing it. | |
| 403 GURL image_url(test_server_->GetURL(image_path)); | |
|
Peter Kasting
2014/12/12 00:35:51
Nit: I would probably inline this into the next st
jbroman
2014/12/12 01:10:46
still doesn't fit on one line, though, so I mildly
| |
| 404 GURL page("data:text/html,<img src='" + image_url.spec() + "'>"); | |
| 405 ui_test_utils::NavigateToURL(browser_, page); | |
| 406 } | |
| 407 | |
| 408 void AttemptImageSearch() { | |
| 409 // Right-click where the image should be. | |
| 410 // |menu_observer_| will cause the search-by-image menu item to be clicked. | |
| 411 content::WebContents* tab = | |
| 412 browser_->tab_strip_model()->GetActiveWebContents(); | |
| 413 content::SimulateMouseClickAt(tab, 0, blink::WebMouseEvent::ButtonRight, | |
| 414 gfx::Point(15, 15)); | |
| 415 } | |
| 416 | |
| 417 private: | |
| 418 void SetupImageSearchEngine() { | |
| 419 static const char kShortName[] = "test"; | |
| 420 static const char kSearchURL[] = "search?q={searchTerms}"; | |
| 421 static const char kImageSearchPostParams[] = | |
| 422 "thumb={google:imageThumbnail}"; | |
| 423 | |
| 424 TemplateURLService* model = | |
| 425 TemplateURLServiceFactory::GetForProfile(browser_->profile()); | |
| 426 ASSERT_TRUE(model); | |
| 427 ui_test_utils::WaitForTemplateURLServiceToLoad(model); | |
| 428 ASSERT_TRUE(model->loaded()); | |
| 429 | |
| 430 TemplateURLData data; | |
| 431 data.short_name = base::ASCIIToUTF16(kShortName); | |
| 432 data.SetKeyword(data.short_name); | |
| 433 data.SetURL(test_server_->GetURL(kSearchURL).spec()); | |
| 434 data.image_url = test_server_->GetURL(kImageSearchURL).spec(); | |
| 435 data.image_url_post_params = kImageSearchPostParams; | |
| 436 | |
| 437 // The model takes ownership of |template_url|. | |
| 438 TemplateURL* template_url = new TemplateURL(data); | |
| 439 ASSERT_TRUE(model->Add(template_url)); | |
| 440 model->SetUserSelectedDefaultSearchProvider(template_url); | |
| 441 } | |
| 442 | |
| 443 ContextMenuNotificationObserver menu_observer_; | |
| 444 net::SpawnedTestServer* test_server_; | |
| 445 Browser* browser_; | |
| 446 | |
| 447 DISALLOW_COPY_AND_ASSIGN(ImageSearchTestHelper); | |
| 448 }; | |
| 449 | |
| 450 const char ImageSearchTestHelper::kImageSearchURL[] = "imagesearch"; | |
| 451 | |
| 452 IN_PROC_BROWSER_TEST_F(ContextMenuBrowserTest, ImageSearchWithValidImage) { | |
| 453 static const char kValidImage[] = "files/image_search/valid.png"; | |
| 454 ImageSearchTestHelper helper(test_server(), browser()); | |
| 455 helper.SetupAndLoadImagePage(kValidImage); | |
| 456 | |
| 457 ui_test_utils::WindowedTabAddedNotificationObserver tab_observer( | |
| 458 content::NotificationService::AllSources()); | |
| 459 helper.AttemptImageSearch(); | |
| 460 | |
| 461 // The browser should open a new tab for an image search. | |
| 462 tab_observer.Wait(); | |
| 463 content::WebContents* new_tab = tab_observer.GetTab(); | |
| 464 content::WaitForLoadStop(new_tab); | |
| 465 EXPECT_EQ(test_server()->GetURL(ImageSearchTestHelper::kImageSearchURL), | |
| 466 new_tab->GetURL()); | |
| 467 } | |
| 468 | |
| 469 IN_PROC_BROWSER_TEST_F(ContextMenuBrowserTest, ImageSearchWithCorruptImage) { | |
| 470 static const char kCorruptImage[] = "files/image_search/corrupt.png"; | |
| 471 ImageSearchTestHelper helper(test_server(), browser()); | |
| 472 helper.SetupAndLoadImagePage(kCorruptImage); | |
| 473 | |
| 474 content::WebContents* tab = | |
| 475 browser()->tab_strip_model()->GetActiveWebContents(); | |
| 476 ThumbnailResponseWatcher watcher(tab->GetRenderProcessHost()); | |
| 477 helper.AttemptImageSearch(); | |
| 478 | |
| 479 // The browser should receive a response from the renderer, because the | |
| 480 // renderer should not crash. | |
| 481 EXPECT_EQ(ThumbnailResponseWatcher::THUMBNAIL_RECEIVED, watcher.Wait()); | |
| 482 } | |
| 483 | |
| 291 } // namespace | 484 } // namespace |
| OLD | NEW |