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
31 namespace {
32
33 class TestData {
34 public:
GetInstance()35 static TestData* GetInstance() {
36 return Singleton<TestData>::get();
37 }
38
GetTestData()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:
TestData()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.
63 class SimpleTestJob : public net::URLRequestTestJob {
64 public:
SimpleTestJob(net::URLRequest * request)65 explicit SimpleTestJob(net::URLRequest* request)
66 : net::URLRequestTestJob(request, test_headers(),
67 TestData::GetInstance()->GetTestData(), true) {}
68
GetResponseInfo(net::HttpResponseInfo * info)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:
~SimpleTestJob()89 ~SimpleTestJob() {}
90 };
91
92 class TestController {
93 public:
GetInstance()94 static TestController* GetInstance() {
95 return Singleton<TestController>::get();
96 }
set_result(bool value)97 void set_result(bool value) {
98 result_ = value;
99 }
result()100 bool result() {
101 return result_;
102 }
set_expected_url(const GURL & url)103 void set_expected_url(const GURL& url) {
104 expected_url_ = url;
105 }
expected_url()106 const GURL expected_url() {
107 return expected_url_;
108 }
set_delegate(TestDelegate * delegate)109 void set_delegate(TestDelegate* delegate) {
110 delegate_ = delegate;
111 }
delegate()112 TestDelegate* delegate() {
113 return delegate_;
114 }
set_use_delegate(bool value)115 void set_use_delegate(bool value) {
116 use_delegate_ = value;
117 }
use_delegate()118 bool use_delegate() {
119 return use_delegate_;
120 }
121 private:
TestController()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
137 class PrintDialogCloudTest : public InProcessBrowserTest {
138 public:
PrintDialogCloudTest()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:
AutoQuitDelegate()148 AutoQuitDelegate() {}
149
OnResponseCompleted(net::URLRequest * request)150 virtual void OnResponseCompleted(net::URLRequest* request) {
151 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
152 new MessageLoop::QuitTask());
153 }
154 };
155
SetUp()156 virtual void SetUp() {
157 TestController::GetInstance()->set_result(false);
158 InProcessBrowserTest::SetUp();
159 }
160
TearDown()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.
AddTestHandlers()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
CreateDialogForTest()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
Factory(net::URLRequest * request,const std::string & scheme)216 net::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
IN_PROC_BROWSER_TEST_F(PrintDialogCloudTest,HandlersRegistered)227 IN_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.
IN_PROC_BROWSER_TEST_F(PrintDialogCloudTest,DISABLED_DialogGrabbed)243 IN_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