// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/printing/print_dialog_cloud.h" #include "chrome/browser/printing/print_dialog_cloud_internal.h" #include <functional> #include "base/file_path.h" #include "base/file_util.h" #include "base/memory/singleton.h" #include "base/path_service.h" #include "base/threading/thread_restrictions.h" #include "base/utf_string_conversions.h" #include "base/values.h" #include "chrome/browser/printing/cloud_print/cloud_print_url.h" #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/webui/chrome_url_data_manager.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/url_constants.h" #include "chrome/test/in_process_browser_test.h" #include "chrome/test/ui_test_utils.h" #include "content/browser/browser_thread.h" #include "content/browser/renderer_host/render_view_host.h" #include "content/browser/tab_contents/tab_contents.h" #include "net/url_request/url_request_filter.h" #include "net/url_request/url_request_test_job.h" #include "net/url_request/url_request_test_util.h" namespace { class TestData { public: static TestData* GetInstance() { return Singleton<TestData>::get(); } const char* GetTestData() { // Fetching this data blocks the IO thread, but we don't really care because // this is a test. base::ThreadRestrictions::ScopedAllowIO allow_io; if (test_data_.empty()) { FilePath test_data_directory; PathService::Get(chrome::DIR_TEST_DATA, &test_data_directory); FilePath test_file = test_data_directory.AppendASCII("printing/cloud_print_uitest.html"); file_util::ReadFileToString(test_file, &test_data_); } return test_data_.c_str(); } private: TestData() {} std::string test_data_; friend struct DefaultSingletonTraits<TestData>; }; // A simple test net::URLRequestJob. We don't care what it does, only that // whether it starts and finishes. class SimpleTestJob : public net::URLRequestTestJob { public: explicit SimpleTestJob(net::URLRequest* request) : net::URLRequestTestJob(request, test_headers(), TestData::GetInstance()->GetTestData(), true) {} virtual void GetResponseInfo(net::HttpResponseInfo* info) { net::URLRequestTestJob::GetResponseInfo(info); if (request_->url().SchemeIsSecure()) { // Make up a fake certificate for this response since we don't have // access to the real SSL info. const char* kCertIssuer = "Chrome Internal"; const int kLifetimeDays = 100; info->ssl_info.cert = new net::X509Certificate(request_->url().GetWithEmptyPath().spec(), kCertIssuer, base::Time::Now(), base::Time::Now() + base::TimeDelta::FromDays(kLifetimeDays)); info->ssl_info.cert_status = 0; info->ssl_info.security_bits = -1; } } private: ~SimpleTestJob() {} }; class TestController { public: static TestController* GetInstance() { return Singleton<TestController>::get(); } void set_result(bool value) { result_ = value; } bool result() { return result_; } void set_expected_url(const GURL& url) { expected_url_ = url; } const GURL expected_url() { return expected_url_; } void set_delegate(TestDelegate* delegate) { delegate_ = delegate; } TestDelegate* delegate() { return delegate_; } void set_use_delegate(bool value) { use_delegate_ = value; } bool use_delegate() { return use_delegate_; } private: TestController() : result_(false), use_delegate_(false), delegate_(NULL) {} bool result_; bool use_delegate_; GURL expected_url_; TestDelegate* delegate_; friend struct DefaultSingletonTraits<TestController>; }; } // namespace class PrintDialogCloudTest : public InProcessBrowserTest { public: PrintDialogCloudTest() : handler_added_(false) { PathService::Get(chrome::DIR_TEST_DATA, &test_data_directory_); } // Must be static for handing into AddHostnameHandler. static net::URLRequest::ProtocolFactory Factory; class AutoQuitDelegate : public TestDelegate { public: AutoQuitDelegate() {} virtual void OnResponseCompleted(net::URLRequest* request) { BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, new MessageLoop::QuitTask()); } }; virtual void SetUp() { TestController::GetInstance()->set_result(false); InProcessBrowserTest::SetUp(); } virtual void TearDown() { if (handler_added_) { net::URLRequestFilter* filter = net::URLRequestFilter::GetInstance(); filter->RemoveHostnameHandler(scheme_, host_name_); handler_added_ = false; TestController::GetInstance()->set_delegate(NULL); } InProcessBrowserTest::TearDown(); } // Normally this is something I would expect could go into SetUp(), // but there seems to be some timing or ordering related issue with // the test harness that made that flaky. Calling this from the // individual test functions seems to fix that. void AddTestHandlers() { if (!handler_added_) { net::URLRequestFilter* filter = net::URLRequestFilter::GetInstance(); GURL cloud_print_service_url = CloudPrintURL(browser()->profile()). GetCloudPrintServiceURL(); scheme_ = cloud_print_service_url.scheme(); host_name_ = cloud_print_service_url.host(); filter->AddHostnameHandler(scheme_, host_name_, &PrintDialogCloudTest::Factory); handler_added_ = true; GURL cloud_print_dialog_url = CloudPrintURL(browser()->profile()). GetCloudPrintServiceDialogURL(); TestController::GetInstance()->set_expected_url(cloud_print_dialog_url); TestController::GetInstance()->set_delegate(&delegate_); } CreateDialogForTest(); } void CreateDialogForTest() { FilePath path_to_pdf = test_data_directory_.AppendASCII("printing/cloud_print_uitest.pdf"); BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, NewRunnableFunction(&internal_cloud_print_helpers::CreateDialogImpl, path_to_pdf, string16(), std::string("application/pdf"), true)); } bool handler_added_; std::string scheme_; std::string host_name_; FilePath test_data_directory_; AutoQuitDelegate delegate_; }; net::URLRequestJob* PrintDialogCloudTest::Factory(net::URLRequest* request, const std::string& scheme) { if (TestController::GetInstance()->use_delegate()) request->set_delegate(TestController::GetInstance()->delegate()); if (request && (request->url() == TestController::GetInstance()->expected_url())) { TestController::GetInstance()->set_result(true); } return new SimpleTestJob(request); } IN_PROC_BROWSER_TEST_F(PrintDialogCloudTest, HandlersRegistered) { BrowserList::SetLastActive(browser()); ASSERT_TRUE(BrowserList::GetLastActive()); AddTestHandlers(); TestController::GetInstance()->set_use_delegate(true); ui_test_utils::RunMessageLoop(); ASSERT_TRUE(TestController::GetInstance()->result()); } #if defined(OS_CHROMEOS) // Disabled until the extern URL is live so that the Print menu item // can be enabled for Chromium OS. IN_PROC_BROWSER_TEST_F(PrintDialogCloudTest, DISABLED_DialogGrabbed) { BrowserList::SetLastActive(browser()); ASSERT_TRUE(BrowserList::GetLastActive()); AddTestHandlers(); // This goes back one step further for the Chrome OS case, to making // sure 'window.print()' gets to the right place. ASSERT_TRUE(browser()->GetSelectedTabContents()); ASSERT_TRUE(browser()->GetSelectedTabContents()->render_view_host()); string16 window_print = ASCIIToUTF16("window.print()"); browser()->GetSelectedTabContents()->render_view_host()-> ExecuteJavascriptInWebFrame(string16(), window_print); ui_test_utils::RunMessageLoop(); ASSERT_TRUE(TestController::GetInstance()->result()); } #endif