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/printing/print_dialog_cloud.h" 6#include "chrome/browser/printing/print_dialog_cloud_internal.h" 7 8#include <functional> 9 10#include "base/file_path.h" 11#include "base/file_util.h" 12#include "base/memory/singleton.h" 13#include "base/path_service.h" 14#include "base/threading/thread_restrictions.h" 15#include "base/utf_string_conversions.h" 16#include "base/values.h" 17#include "chrome/browser/printing/cloud_print/cloud_print_url.h" 18#include "chrome/browser/ui/browser_list.h" 19#include "chrome/browser/ui/webui/chrome_url_data_manager.h" 20#include "chrome/common/chrome_paths.h" 21#include "chrome/common/url_constants.h" 22#include "chrome/test/in_process_browser_test.h" 23#include "chrome/test/ui_test_utils.h" 24#include "content/browser/browser_thread.h" 25#include "content/browser/renderer_host/render_view_host.h" 26#include "content/browser/tab_contents/tab_contents.h" 27#include "net/url_request/url_request_filter.h" 28#include "net/url_request/url_request_test_job.h" 29#include "net/url_request/url_request_test_util.h" 30 31namespace { 32 33class TestData { 34 public: 35 static TestData* GetInstance() { 36 return Singleton<TestData>::get(); 37 } 38 39 const char* GetTestData() { 40 // Fetching this data blocks the IO thread, but we don't really care because 41 // this is a test. 42 base::ThreadRestrictions::ScopedAllowIO allow_io; 43 44 if (test_data_.empty()) { 45 FilePath test_data_directory; 46 PathService::Get(chrome::DIR_TEST_DATA, &test_data_directory); 47 FilePath test_file = 48 test_data_directory.AppendASCII("printing/cloud_print_uitest.html"); 49 file_util::ReadFileToString(test_file, &test_data_); 50 } 51 return test_data_.c_str(); 52 } 53 private: 54 TestData() {} 55 56 std::string test_data_; 57 58 friend struct DefaultSingletonTraits<TestData>; 59}; 60 61// A simple test net::URLRequestJob. We don't care what it does, only that 62// whether it starts and finishes. 63class SimpleTestJob : public net::URLRequestTestJob { 64 public: 65 explicit SimpleTestJob(net::URLRequest* request) 66 : net::URLRequestTestJob(request, test_headers(), 67 TestData::GetInstance()->GetTestData(), true) {} 68 69 virtual void GetResponseInfo(net::HttpResponseInfo* info) { 70 net::URLRequestTestJob::GetResponseInfo(info); 71 if (request_->url().SchemeIsSecure()) { 72 // Make up a fake certificate for this response since we don't have 73 // access to the real SSL info. 74 const char* kCertIssuer = "Chrome Internal"; 75 const int kLifetimeDays = 100; 76 77 info->ssl_info.cert = 78 new net::X509Certificate(request_->url().GetWithEmptyPath().spec(), 79 kCertIssuer, 80 base::Time::Now(), 81 base::Time::Now() + 82 base::TimeDelta::FromDays(kLifetimeDays)); 83 info->ssl_info.cert_status = 0; 84 info->ssl_info.security_bits = -1; 85 } 86 } 87 88 private: 89 ~SimpleTestJob() {} 90}; 91 92class TestController { 93 public: 94 static TestController* GetInstance() { 95 return Singleton<TestController>::get(); 96 } 97 void set_result(bool value) { 98 result_ = value; 99 } 100 bool result() { 101 return result_; 102 } 103 void set_expected_url(const GURL& url) { 104 expected_url_ = url; 105 } 106 const GURL expected_url() { 107 return expected_url_; 108 } 109 void set_delegate(TestDelegate* delegate) { 110 delegate_ = delegate; 111 } 112 TestDelegate* delegate() { 113 return delegate_; 114 } 115 void set_use_delegate(bool value) { 116 use_delegate_ = value; 117 } 118 bool use_delegate() { 119 return use_delegate_; 120 } 121 private: 122 TestController() 123 : result_(false), 124 use_delegate_(false), 125 delegate_(NULL) {} 126 127 bool result_; 128 bool use_delegate_; 129 GURL expected_url_; 130 TestDelegate* delegate_; 131 132 friend struct DefaultSingletonTraits<TestController>; 133}; 134 135} // namespace 136 137class PrintDialogCloudTest : public InProcessBrowserTest { 138 public: 139 PrintDialogCloudTest() : handler_added_(false) { 140 PathService::Get(chrome::DIR_TEST_DATA, &test_data_directory_); 141 } 142 143 // Must be static for handing into AddHostnameHandler. 144 static net::URLRequest::ProtocolFactory Factory; 145 146 class AutoQuitDelegate : public TestDelegate { 147 public: 148 AutoQuitDelegate() {} 149 150 virtual void OnResponseCompleted(net::URLRequest* request) { 151 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 152 new MessageLoop::QuitTask()); 153 } 154 }; 155 156 virtual void SetUp() { 157 TestController::GetInstance()->set_result(false); 158 InProcessBrowserTest::SetUp(); 159 } 160 161 virtual void TearDown() { 162 if (handler_added_) { 163 net::URLRequestFilter* filter = net::URLRequestFilter::GetInstance(); 164 filter->RemoveHostnameHandler(scheme_, host_name_); 165 handler_added_ = false; 166 TestController::GetInstance()->set_delegate(NULL); 167 } 168 InProcessBrowserTest::TearDown(); 169 } 170 171 // Normally this is something I would expect could go into SetUp(), 172 // but there seems to be some timing or ordering related issue with 173 // the test harness that made that flaky. Calling this from the 174 // individual test functions seems to fix that. 175 void AddTestHandlers() { 176 if (!handler_added_) { 177 net::URLRequestFilter* filter = net::URLRequestFilter::GetInstance(); 178 GURL cloud_print_service_url = 179 CloudPrintURL(browser()->profile()). 180 GetCloudPrintServiceURL(); 181 scheme_ = cloud_print_service_url.scheme(); 182 host_name_ = cloud_print_service_url.host(); 183 filter->AddHostnameHandler(scheme_, host_name_, 184 &PrintDialogCloudTest::Factory); 185 handler_added_ = true; 186 187 GURL cloud_print_dialog_url = 188 CloudPrintURL(browser()->profile()). 189 GetCloudPrintServiceDialogURL(); 190 TestController::GetInstance()->set_expected_url(cloud_print_dialog_url); 191 TestController::GetInstance()->set_delegate(&delegate_); 192 } 193 194 CreateDialogForTest(); 195 } 196 197 void CreateDialogForTest() { 198 FilePath path_to_pdf = 199 test_data_directory_.AppendASCII("printing/cloud_print_uitest.pdf"); 200 BrowserThread::PostTask( 201 BrowserThread::UI, FROM_HERE, 202 NewRunnableFunction(&internal_cloud_print_helpers::CreateDialogImpl, 203 path_to_pdf, 204 string16(), 205 std::string("application/pdf"), 206 true)); 207 } 208 209 bool handler_added_; 210 std::string scheme_; 211 std::string host_name_; 212 FilePath test_data_directory_; 213 AutoQuitDelegate delegate_; 214}; 215 216net::URLRequestJob* PrintDialogCloudTest::Factory(net::URLRequest* request, 217 const std::string& scheme) { 218 if (TestController::GetInstance()->use_delegate()) 219 request->set_delegate(TestController::GetInstance()->delegate()); 220 if (request && 221 (request->url() == TestController::GetInstance()->expected_url())) { 222 TestController::GetInstance()->set_result(true); 223 } 224 return new SimpleTestJob(request); 225} 226 227IN_PROC_BROWSER_TEST_F(PrintDialogCloudTest, HandlersRegistered) { 228 BrowserList::SetLastActive(browser()); 229 ASSERT_TRUE(BrowserList::GetLastActive()); 230 231 AddTestHandlers(); 232 233 TestController::GetInstance()->set_use_delegate(true); 234 235 ui_test_utils::RunMessageLoop(); 236 237 ASSERT_TRUE(TestController::GetInstance()->result()); 238} 239 240#if defined(OS_CHROMEOS) 241// Disabled until the extern URL is live so that the Print menu item 242// can be enabled for Chromium OS. 243IN_PROC_BROWSER_TEST_F(PrintDialogCloudTest, DISABLED_DialogGrabbed) { 244 BrowserList::SetLastActive(browser()); 245 ASSERT_TRUE(BrowserList::GetLastActive()); 246 247 AddTestHandlers(); 248 249 // This goes back one step further for the Chrome OS case, to making 250 // sure 'window.print()' gets to the right place. 251 ASSERT_TRUE(browser()->GetSelectedTabContents()); 252 ASSERT_TRUE(browser()->GetSelectedTabContents()->render_view_host()); 253 254 string16 window_print = ASCIIToUTF16("window.print()"); 255 browser()->GetSelectedTabContents()->render_view_host()-> 256 ExecuteJavascriptInWebFrame(string16(), window_print); 257 258 ui_test_utils::RunMessageLoop(); 259 260 ASSERT_TRUE(TestController::GetInstance()->result()); 261} 262#endif 263