Home | History | Annotate | Download | only in printing
      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 "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/bind.h"
     11 #include "base/file_util.h"
     12 #include "base/files/file_path.h"
     13 #include "base/memory/singleton.h"
     14 #include "base/path_service.h"
     15 #include "base/strings/utf_string_conversions.h"
     16 #include "base/threading/thread_restrictions.h"
     17 #include "base/values.h"
     18 #include "chrome/browser/printing/cloud_print/cloud_print_url.h"
     19 #include "chrome/browser/profiles/profile.h"
     20 #include "chrome/browser/ui/browser.h"
     21 #include "chrome/browser/ui/browser_window.h"
     22 #include "chrome/common/chrome_paths.h"
     23 #include "chrome/common/url_constants.h"
     24 #include "chrome/test/base/in_process_browser_test.h"
     25 #include "chrome/test/base/ui_test_utils.h"
     26 #include "content/public/browser/notification_service.h"
     27 #include "content/public/browser/notification_types.h"
     28 #include "content/public/browser/render_view_host.h"
     29 #include "content/public/browser/web_contents.h"
     30 #include "content/public/test/test_browser_thread.h"
     31 #include "net/url_request/url_request.h"
     32 #include "net/url_request/url_request_filter.h"
     33 #include "net/url_request/url_request_test_job.h"
     34 #include "net/url_request/url_request_test_util.h"
     35 #include "ui/base/test/ui_controls.h"
     36 
     37 using content::BrowserThread;
     38 
     39 namespace {
     40 
     41 class TestData {
     42  public:
     43   static TestData* GetInstance() {
     44     return Singleton<TestData>::get();
     45   }
     46 
     47   const char* GetTestData() {
     48     // Fetching this data blocks the IO thread, but we don't really care because
     49     // this is a test.
     50     base::ThreadRestrictions::ScopedAllowIO allow_io;
     51 
     52     if (test_data_.empty()) {
     53       base::FilePath test_data_directory;
     54       PathService::Get(chrome::DIR_TEST_DATA, &test_data_directory);
     55       base::FilePath test_file =
     56           test_data_directory.AppendASCII("printing/cloud_print_uitest.html");
     57       file_util::ReadFileToString(test_file, &test_data_);
     58     }
     59     return test_data_.c_str();
     60   }
     61  private:
     62   TestData() {}
     63 
     64   std::string test_data_;
     65 
     66   friend struct DefaultSingletonTraits<TestData>;
     67 };
     68 
     69 // A simple test net::URLRequestJob. We don't care what it does, only that
     70 // whether it starts and finishes.
     71 class SimpleTestJob : public net::URLRequestTestJob {
     72  public:
     73   SimpleTestJob(net::URLRequest* request,
     74                 net::NetworkDelegate* network_delegate)
     75       : net::URLRequestTestJob(request,
     76                                network_delegate,
     77                                test_headers(),
     78                                TestData::GetInstance()->GetTestData(),
     79                                true) {}
     80 
     81   virtual void GetResponseInfo(net::HttpResponseInfo* info) OVERRIDE {
     82     net::URLRequestTestJob::GetResponseInfo(info);
     83     if (request_->url().SchemeIsSecure()) {
     84       // Make up a fake certificate for this response since we don't have
     85       // access to the real SSL info.
     86       const char* kCertIssuer = "Chrome Internal";
     87       const int kLifetimeDays = 100;
     88 
     89       info->ssl_info.cert =
     90           new net::X509Certificate(request_->url().GetWithEmptyPath().spec(),
     91                                    kCertIssuer,
     92                                    base::Time::Now(),
     93                                    base::Time::Now() +
     94                                    base::TimeDelta::FromDays(kLifetimeDays));
     95       info->ssl_info.cert_status = 0;
     96       info->ssl_info.security_bits = -1;
     97     }
     98   }
     99 
    100  private:
    101   virtual ~SimpleTestJob() {}
    102 };
    103 
    104 class TestController {
    105  public:
    106   static TestController* GetInstance() {
    107     return Singleton<TestController>::get();
    108   }
    109   void set_result(bool value) {
    110     result_ = value;
    111   }
    112   bool result() {
    113     return result_;
    114   }
    115   void set_expected_url(const GURL& url) {
    116     expected_url_ = url;
    117   }
    118   const GURL expected_url() {
    119     return expected_url_;
    120   }
    121   void set_delegate(net::TestDelegate* delegate) {
    122     delegate_ = delegate;
    123   }
    124   net::TestDelegate* delegate() {
    125     return delegate_;
    126   }
    127   void set_use_delegate(bool value) {
    128     use_delegate_ = value;
    129   }
    130   bool use_delegate() {
    131     return use_delegate_;
    132   }
    133  private:
    134   TestController()
    135       : result_(false),
    136         use_delegate_(false),
    137         delegate_(NULL) {}
    138 
    139   bool result_;
    140   bool use_delegate_;
    141   GURL expected_url_;
    142   net::TestDelegate* delegate_;
    143 
    144   friend struct DefaultSingletonTraits<TestController>;
    145 };
    146 
    147 }  // namespace
    148 
    149 class PrintDialogCloudTest : public InProcessBrowserTest {
    150  public:
    151   PrintDialogCloudTest() : handler_added_(false) {
    152     PathService::Get(chrome::DIR_TEST_DATA, &test_data_directory_);
    153   }
    154 
    155   // Must be static for handing into AddHostnameHandler.
    156   static net::URLRequest::ProtocolFactory Factory;
    157 
    158   class AutoQuitDelegate : public net::TestDelegate {
    159    public:
    160     AutoQuitDelegate() {}
    161 
    162     virtual void OnResponseCompleted(net::URLRequest* request) OVERRIDE {
    163       BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
    164                               base::MessageLoop::QuitClosure());
    165     }
    166   };
    167 
    168   virtual void SetUp() OVERRIDE {
    169     TestController::GetInstance()->set_result(false);
    170     InProcessBrowserTest::SetUp();
    171   }
    172 
    173   virtual void TearDown() OVERRIDE {
    174     if (handler_added_) {
    175       BrowserThread::PostTask(
    176           BrowserThread::IO, FROM_HERE,
    177           base::Bind(UnregisterTestHandlers, scheme_, host_name_));
    178       handler_added_ = false;
    179       TestController::GetInstance()->set_delegate(NULL);
    180     }
    181     InProcessBrowserTest::TearDown();
    182   }
    183 
    184   // Normally this is something I would expect could go into SetUp(),
    185   // but there seems to be some timing or ordering related issue with
    186   // the test harness that made that flaky.  Calling this from the
    187   // individual test functions seems to fix that.
    188   void AddTestHandlers() {
    189     if (!handler_added_) {
    190       GURL cloud_print_service_url =
    191           CloudPrintURL(browser()->profile()).
    192           GetCloudPrintServiceURL();
    193       scheme_ = cloud_print_service_url.scheme();
    194       host_name_ = cloud_print_service_url.host();
    195       BrowserThread::PostTask(
    196           BrowserThread::IO, FROM_HERE,
    197           base::Bind(RegisterTestHandlers, scheme_, host_name_));
    198       handler_added_ = true;
    199 
    200       GURL cloud_print_dialog_url =
    201           CloudPrintURL(browser()->profile()).
    202           GetCloudPrintServiceDialogURL();
    203       TestController::GetInstance()->set_expected_url(cloud_print_dialog_url);
    204       TestController::GetInstance()->set_delegate(&delegate_);
    205     }
    206 
    207     CreateDialogForTest();
    208   }
    209 
    210   void CreateDialogForTest() {
    211     base::FilePath path_to_pdf =
    212         test_data_directory_.AppendASCII("printing/cloud_print_uitest.pdf");
    213     BrowserThread::PostTask(
    214         BrowserThread::UI, FROM_HERE,
    215         base::Bind(&print_dialog_cloud::CreatePrintDialogForFile,
    216                    browser()->profile(), browser()->window()->GetNativeWindow(),
    217                    path_to_pdf, string16(), string16(),
    218                    std::string("application/pdf"), false));
    219   }
    220 
    221  private:
    222   static void RegisterTestHandlers(const std::string& scheme,
    223                        const std::string& host_name) {
    224     net::URLRequestFilter::GetInstance()->AddHostnameHandler(
    225         scheme, host_name, &PrintDialogCloudTest::Factory);
    226   }
    227   static void UnregisterTestHandlers(const std::string& scheme,
    228                          const std::string& host_name) {
    229     net::URLRequestFilter::GetInstance()->RemoveHostnameHandler(scheme,
    230                                                                 host_name);
    231   }
    232 
    233   bool handler_added_;
    234   std::string scheme_;
    235   std::string host_name_;
    236   base::FilePath test_data_directory_;
    237   AutoQuitDelegate delegate_;
    238 };
    239 
    240 net::URLRequestJob* PrintDialogCloudTest::Factory(
    241     net::URLRequest* request,
    242     net::NetworkDelegate* network_delegate,
    243     const std::string& scheme) {
    244   if (request &&
    245       (request->url() == TestController::GetInstance()->expected_url())) {
    246     if (TestController::GetInstance()->use_delegate())
    247       request->set_delegate(TestController::GetInstance()->delegate());
    248     TestController::GetInstance()->set_result(true);
    249     return new SimpleTestJob(request, network_delegate);
    250   }
    251   return new net::URLRequestTestJob(request,
    252                                     network_delegate,
    253                                     net::URLRequestTestJob::test_headers(),
    254                                     std::string(),
    255                                     true);
    256 }
    257 
    258 IN_PROC_BROWSER_TEST_F(PrintDialogCloudTest, HandlersRegistered) {
    259   AddTestHandlers();
    260 
    261   TestController::GetInstance()->set_use_delegate(true);
    262 
    263   content::RunMessageLoop();
    264 
    265   ASSERT_TRUE(TestController::GetInstance()->result());
    266 
    267   // Close the dialog before finishing the test.
    268   content::WindowedNotificationObserver tab_closed_observer(
    269       content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
    270       content::NotificationService::AllSources());
    271 
    272   // Can't use ui_test_utils::SendKeyPressSync or
    273   // ui_test_utils::SendKeyPressAndWait due to a race condition with closing
    274   // the window. See http://crbug.com/111269
    275   BrowserWindow* window = browser()->window();
    276   ASSERT_TRUE(window);
    277   gfx::NativeWindow native_window = window->GetNativeWindow();
    278   ASSERT_TRUE(native_window);
    279   bool key_sent = ui_controls::SendKeyPress(native_window, ui::VKEY_ESCAPE,
    280                                             false, false, false, false);
    281   EXPECT_TRUE(key_sent);
    282   if (key_sent)
    283     tab_closed_observer.Wait();
    284 }
    285