Home | History | Annotate | Download | only in drive
      1 // Copyright 2013 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/chromeos/drive/drive_url_request_job.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/memory/ref_counted.h"
      9 #include "base/memory/scoped_ptr.h"
     10 #include "base/run_loop.h"
     11 #include "base/sequenced_task_runner.h"
     12 #include "base/threading/sequenced_worker_pool.h"
     13 #include "base/threading/thread.h"
     14 #include "chrome/browser/chromeos/drive/drive_file_stream_reader.h"
     15 #include "chrome/browser/chromeos/drive/fake_file_system.h"
     16 #include "chrome/browser/chromeos/drive/file_system_util.h"
     17 #include "chrome/browser/chromeos/drive/test_util.h"
     18 #include "chrome/browser/drive/fake_drive_service.h"
     19 #include "chrome/browser/drive/test_util.h"
     20 #include "chrome/common/url_constants.h"
     21 #include "content/public/browser/browser_thread.h"
     22 #include "content/public/test/test_browser_thread_bundle.h"
     23 #include "google_apis/drive/test_util.h"
     24 #include "net/base/request_priority.h"
     25 #include "net/base/test_completion_callback.h"
     26 #include "net/http/http_byte_range.h"
     27 #include "net/url_request/url_request_test_util.h"
     28 #include "testing/gtest/include/gtest/gtest.h"
     29 #include "url/gurl.h"
     30 
     31 namespace drive {
     32 namespace {
     33 
     34 // A simple URLRequestJobFactory implementation to create DriveURLRequestJob.
     35 class TestURLRequestJobFactory : public net::URLRequestJobFactory {
     36  public:
     37   TestURLRequestJobFactory(
     38       const DriveURLRequestJob::FileSystemGetter& file_system_getter,
     39       base::SequencedTaskRunner* sequenced_task_runner)
     40       : file_system_getter_(file_system_getter),
     41         sequenced_task_runner_(sequenced_task_runner) {
     42   }
     43 
     44   virtual ~TestURLRequestJobFactory() {}
     45 
     46   // net::URLRequestJobFactory override:
     47   virtual net::URLRequestJob* MaybeCreateJobWithProtocolHandler(
     48       const std::string& scheme,
     49       net::URLRequest* request,
     50       net::NetworkDelegate* network_delegate) const OVERRIDE {
     51     return new DriveURLRequestJob(file_system_getter_,
     52                                   sequenced_task_runner_.get(),
     53                                   request,
     54                                   network_delegate);
     55   }
     56 
     57   virtual bool IsHandledProtocol(const std::string& scheme) const OVERRIDE {
     58     return scheme == chrome::kDriveScheme;
     59   }
     60 
     61   virtual bool IsHandledURL(const GURL& url) const OVERRIDE {
     62     return url.is_valid() && IsHandledProtocol(url.scheme());
     63   }
     64 
     65   virtual bool IsSafeRedirectTarget(const GURL& location) const OVERRIDE {
     66     return true;
     67   }
     68 
     69  private:
     70   const DriveURLRequestJob::FileSystemGetter file_system_getter_;
     71   scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner_;
     72 
     73   DISALLOW_COPY_AND_ASSIGN(TestURLRequestJobFactory);
     74 };
     75 
     76 class TestDelegate : public net::TestDelegate {
     77  public:
     78   TestDelegate() {}
     79 
     80   const GURL& redirect_url() const { return redirect_url_; }
     81 
     82   // net::TestDelegate override.
     83   virtual void OnReceivedRedirect(net::URLRequest* request,
     84                                   const GURL& new_url,
     85                                   bool* defer_redirect) OVERRIDE{
     86     redirect_url_ = new_url;
     87     net::TestDelegate::OnReceivedRedirect(request, new_url, defer_redirect);
     88   }
     89 
     90  private:
     91   GURL redirect_url_;
     92 
     93   DISALLOW_COPY_AND_ASSIGN(TestDelegate);
     94 };
     95 
     96 }  // namespace
     97 
     98 class DriveURLRequestJobTest : public testing::Test {
     99  protected:
    100   DriveURLRequestJobTest()
    101       : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {
    102   }
    103 
    104   virtual ~DriveURLRequestJobTest() {
    105   }
    106 
    107   virtual void SetUp() OVERRIDE {
    108     // Initialize FakeDriveService.
    109     fake_drive_service_.reset(new FakeDriveService);
    110     ASSERT_TRUE(test_util::SetUpTestEntries(fake_drive_service_.get()));
    111 
    112     // Initialize FakeFileSystem.
    113     fake_file_system_.reset(
    114         new test_util::FakeFileSystem(fake_drive_service_.get()));
    115 
    116     scoped_refptr<base::SequencedWorkerPool> blocking_pool =
    117         content::BrowserThread::GetBlockingPool();
    118     test_network_delegate_.reset(new net::TestNetworkDelegate);
    119     test_url_request_job_factory_.reset(new TestURLRequestJobFactory(
    120         base::Bind(&DriveURLRequestJobTest::GetFileSystem,
    121                    base::Unretained(this)),
    122         blocking_pool->GetSequencedTaskRunner(
    123             blocking_pool->GetSequenceToken()).get()));
    124     url_request_context_.reset(new net::URLRequestContext());
    125     url_request_context_->set_job_factory(test_url_request_job_factory_.get());
    126     url_request_context_->set_network_delegate(test_network_delegate_.get());
    127     test_delegate_.reset(new TestDelegate);
    128   }
    129 
    130   FileSystemInterface* GetFileSystem() {
    131     return fake_file_system_.get();
    132   }
    133 
    134   bool ReadDriveFileSync(
    135       const base::FilePath& file_path, std::string* out_content) {
    136     scoped_ptr<base::Thread> worker_thread(
    137         new base::Thread("ReadDriveFileSync"));
    138     if (!worker_thread->Start())
    139       return false;
    140 
    141     scoped_ptr<DriveFileStreamReader> reader(new DriveFileStreamReader(
    142         base::Bind(&DriveURLRequestJobTest::GetFileSystem,
    143                    base::Unretained(this)),
    144         worker_thread->message_loop_proxy().get()));
    145     int error = net::ERR_FAILED;
    146     scoped_ptr<ResourceEntry> entry;
    147     {
    148       base::RunLoop run_loop;
    149       reader->Initialize(
    150           file_path,
    151           net::HttpByteRange(),
    152           google_apis::test_util::CreateQuitCallback(
    153               &run_loop,
    154               google_apis::test_util::CreateCopyResultCallback(
    155                   &error, &entry)));
    156       run_loop.Run();
    157     }
    158     if (error != net::OK || !entry)
    159       return false;
    160 
    161     // Read data from the reader.
    162     std::string content;
    163     if (test_util::ReadAllData(reader.get(), &content) != net::OK)
    164       return false;
    165 
    166     if (static_cast<size_t>(entry->file_info().size()) != content.size())
    167       return false;
    168 
    169     *out_content = content;
    170     return true;
    171   }
    172 
    173   content::TestBrowserThreadBundle thread_bundle_;
    174 
    175   scoped_ptr<FakeDriveService> fake_drive_service_;
    176   scoped_ptr<test_util::FakeFileSystem> fake_file_system_;
    177 
    178   scoped_ptr<net::TestNetworkDelegate> test_network_delegate_;
    179   scoped_ptr<TestURLRequestJobFactory> test_url_request_job_factory_;
    180   scoped_ptr<net::URLRequestContext> url_request_context_;
    181   scoped_ptr<TestDelegate> test_delegate_;
    182 };
    183 
    184 TEST_F(DriveURLRequestJobTest, NonGetMethod) {
    185   net::URLRequest request(GURL("drive:drive/root/File 1.txt"),
    186                           net::DEFAULT_PRIORITY,
    187                           test_delegate_.get(),
    188                           url_request_context_.get());
    189   request.set_method("POST");  // Set non "GET" method.
    190   request.Start();
    191 
    192   base::RunLoop().Run();
    193 
    194   EXPECT_EQ(net::URLRequestStatus::FAILED, request.status().status());
    195   EXPECT_EQ(net::ERR_METHOD_NOT_SUPPORTED, request.status().error());
    196 }
    197 
    198 TEST_F(DriveURLRequestJobTest, RegularFile) {
    199   const GURL kTestUrl("drive:drive/root/File 1.txt");
    200   const base::FilePath kTestFilePath("drive/root/File 1.txt");
    201 
    202   // For the first time, the file should be fetched from the server.
    203   {
    204     net::URLRequest request(kTestUrl,
    205                             net::DEFAULT_PRIORITY,
    206                             test_delegate_.get(),
    207                             url_request_context_.get());
    208     request.Start();
    209 
    210     base::RunLoop().Run();
    211 
    212     EXPECT_EQ(net::URLRequestStatus::SUCCESS, request.status().status());
    213     // It looks weird, but the mime type for the "File 1.txt" is "audio/mpeg"
    214     // on the server.
    215     std::string mime_type;
    216     request.GetMimeType(&mime_type);
    217     EXPECT_EQ("audio/mpeg", mime_type);
    218 
    219     // Reading file must be done after |request| runs, otherwise
    220     // it'll create a local cache file, and we cannot test correctly.
    221     std::string expected_data;
    222     ASSERT_TRUE(ReadDriveFileSync(kTestFilePath, &expected_data));
    223     EXPECT_EQ(expected_data, test_delegate_->data_received());
    224   }
    225 
    226   // For the second time, the locally cached file should be used.
    227   // The caching emulation is done by FakeFileSystem.
    228   {
    229     test_delegate_.reset(new TestDelegate);
    230     net::URLRequest request(GURL("drive:drive/root/File 1.txt"),
    231                             net::DEFAULT_PRIORITY,
    232                             test_delegate_.get(),
    233                             url_request_context_.get());
    234     request.Start();
    235 
    236     base::RunLoop().Run();
    237 
    238     EXPECT_EQ(net::URLRequestStatus::SUCCESS, request.status().status());
    239     std::string mime_type;
    240     request.GetMimeType(&mime_type);
    241     EXPECT_EQ("audio/mpeg", mime_type);
    242 
    243     std::string expected_data;
    244     ASSERT_TRUE(ReadDriveFileSync(kTestFilePath, &expected_data));
    245     EXPECT_EQ(expected_data, test_delegate_->data_received());
    246   }
    247 }
    248 
    249 TEST_F(DriveURLRequestJobTest, HostedDocument) {
    250   // Open a gdoc file.
    251   test_delegate_->set_quit_on_redirect(true);
    252   net::URLRequest request(
    253       GURL("drive:drive/root/Document 1 excludeDir-test.gdoc"),
    254       net::DEFAULT_PRIORITY,
    255       test_delegate_.get(),
    256       url_request_context_.get());
    257   request.Start();
    258 
    259   base::RunLoop().Run();
    260 
    261   EXPECT_EQ(net::URLRequestStatus::SUCCESS, request.status().status());
    262   // Make sure that a hosted document triggers redirection.
    263   EXPECT_TRUE(request.is_redirecting());
    264   EXPECT_TRUE(test_delegate_->redirect_url().is_valid());
    265 }
    266 
    267 TEST_F(DriveURLRequestJobTest, RootDirectory) {
    268   net::URLRequest request(GURL("drive:drive/root"),
    269                           net::DEFAULT_PRIORITY,
    270                           test_delegate_.get(),
    271                           url_request_context_.get());
    272   request.Start();
    273 
    274   base::RunLoop().Run();
    275 
    276   EXPECT_EQ(net::URLRequestStatus::FAILED, request.status().status());
    277   EXPECT_EQ(net::ERR_FAILED, request.status().error());
    278 }
    279 
    280 TEST_F(DriveURLRequestJobTest, Directory) {
    281   net::URLRequest request(GURL("drive:drive/root/Directory 1"),
    282                           net::DEFAULT_PRIORITY,
    283                           test_delegate_.get(),
    284                           url_request_context_.get());
    285   request.Start();
    286 
    287   base::RunLoop().Run();
    288 
    289   EXPECT_EQ(net::URLRequestStatus::FAILED, request.status().status());
    290   EXPECT_EQ(net::ERR_FAILED, request.status().error());
    291 }
    292 
    293 TEST_F(DriveURLRequestJobTest, NonExistingFile) {
    294   net::URLRequest request(GURL("drive:drive/root/non-existing-file.txt"),
    295                           net::DEFAULT_PRIORITY,
    296                           test_delegate_.get(),
    297                           url_request_context_.get());
    298   request.Start();
    299 
    300   base::RunLoop().Run();
    301 
    302   EXPECT_EQ(net::URLRequestStatus::FAILED, request.status().status());
    303   EXPECT_EQ(net::ERR_FILE_NOT_FOUND, request.status().error());
    304 }
    305 
    306 TEST_F(DriveURLRequestJobTest, WrongFormat) {
    307   net::URLRequest request(GURL("drive:"),
    308                           net::DEFAULT_PRIORITY,
    309                           test_delegate_.get(),
    310                           url_request_context_.get());
    311   request.Start();
    312 
    313   base::RunLoop().Run();
    314 
    315   EXPECT_EQ(net::URLRequestStatus::FAILED, request.status().status());
    316   EXPECT_EQ(net::ERR_INVALID_URL, request.status().error());
    317 }
    318 
    319 TEST_F(DriveURLRequestJobTest, Cancel) {
    320   net::URLRequest request(GURL("drive:drive/root/File 1.txt"),
    321                           net::DEFAULT_PRIORITY,
    322                           test_delegate_.get(),
    323                           url_request_context_.get());
    324 
    325   // Start the request, and cancel it immediately after it.
    326   request.Start();
    327   request.Cancel();
    328 
    329   base::RunLoop().Run();
    330 
    331   EXPECT_EQ(net::URLRequestStatus::CANCELED, request.status().status());
    332 }
    333 
    334 TEST_F(DriveURLRequestJobTest, RangeHeader) {
    335   const GURL kTestUrl("drive:drive/root/File 1.txt");
    336   const base::FilePath kTestFilePath("drive/root/File 1.txt");
    337 
    338   net::URLRequest request(kTestUrl,
    339                           net::DEFAULT_PRIORITY,
    340                           test_delegate_.get(),
    341                           url_request_context_.get());
    342 
    343   // Set range header.
    344   request.SetExtraRequestHeaderByName(
    345       "Range", "bytes=3-5", false /* overwrite */);
    346   request.Start();
    347 
    348   base::RunLoop().Run();
    349 
    350   EXPECT_EQ(net::URLRequestStatus::SUCCESS, request.status().status());
    351 
    352   // Reading file must be done after |request| runs, otherwise
    353   // it'll create a local cache file, and we cannot test correctly.
    354   std::string expected_data;
    355   ASSERT_TRUE(ReadDriveFileSync(kTestFilePath, &expected_data));
    356   EXPECT_EQ(expected_data.substr(3, 3), test_delegate_->data_received());
    357 }
    358 
    359 TEST_F(DriveURLRequestJobTest, WrongRangeHeader) {
    360   const GURL kTestUrl("drive:drive/root/File 1.txt");
    361 
    362   net::URLRequest request(kTestUrl,
    363                           net::DEFAULT_PRIORITY,
    364                           test_delegate_.get(),
    365                           url_request_context_.get());
    366 
    367   // Set range header.
    368   request.SetExtraRequestHeaderByName(
    369       "Range", "Wrong Range Header Value", false /* overwrite */);
    370   request.Start();
    371 
    372   base::RunLoop().Run();
    373 
    374   EXPECT_EQ(net::URLRequestStatus::FAILED, request.status().status());
    375   EXPECT_EQ(net::ERR_REQUEST_RANGE_NOT_SATISFIABLE, request.status().error());
    376 }
    377 
    378 }  // namespace drive
    379