drive_url_request_job_unittest.cc revision c5cede9ae108bb15f6b7a8aea21c7e1fefa2834c
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/common/url_constants.h"
20#include "content/public/browser/browser_thread.h"
21#include "content/public/test/test_browser_thread_bundle.h"
22#include "google_apis/drive/test_util.h"
23#include "net/base/request_priority.h"
24#include "net/base/test_completion_callback.h"
25#include "net/http/http_byte_range.h"
26#include "net/url_request/url_request_test_util.h"
27#include "testing/gtest/include/gtest/gtest.h"
28#include "url/gurl.h"
29
30namespace drive {
31namespace {
32
33// A simple URLRequestJobFactory implementation to create DriveURLRequestJob.
34class TestURLRequestJobFactory : public net::URLRequestJobFactory {
35 public:
36  TestURLRequestJobFactory(
37      const DriveURLRequestJob::FileSystemGetter& file_system_getter,
38      base::SequencedTaskRunner* sequenced_task_runner)
39      : file_system_getter_(file_system_getter),
40        sequenced_task_runner_(sequenced_task_runner) {
41  }
42
43  virtual ~TestURLRequestJobFactory() {}
44
45  // net::URLRequestJobFactory override:
46  virtual net::URLRequestJob* MaybeCreateJobWithProtocolHandler(
47      const std::string& scheme,
48      net::URLRequest* request,
49      net::NetworkDelegate* network_delegate) const OVERRIDE {
50    return new DriveURLRequestJob(file_system_getter_,
51                                  sequenced_task_runner_.get(),
52                                  request,
53                                  network_delegate);
54  }
55
56  virtual bool IsHandledProtocol(const std::string& scheme) const OVERRIDE {
57    return scheme == chrome::kDriveScheme;
58  }
59
60  virtual bool IsHandledURL(const GURL& url) const OVERRIDE {
61    return url.is_valid() && IsHandledProtocol(url.scheme());
62  }
63
64  virtual bool IsSafeRedirectTarget(const GURL& location) const OVERRIDE {
65    return true;
66  }
67
68 private:
69  const DriveURLRequestJob::FileSystemGetter file_system_getter_;
70  scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner_;
71
72  DISALLOW_COPY_AND_ASSIGN(TestURLRequestJobFactory);
73};
74
75class TestDelegate : public net::TestDelegate {
76 public:
77  TestDelegate() {}
78
79  const GURL& redirect_url() const { return redirect_url_; }
80
81  // net::TestDelegate override.
82  virtual void OnReceivedRedirect(net::URLRequest* request,
83                                  const GURL& new_url,
84                                  bool* defer_redirect) OVERRIDE{
85    redirect_url_ = new_url;
86    net::TestDelegate::OnReceivedRedirect(request, new_url, defer_redirect);
87  }
88
89 private:
90  GURL redirect_url_;
91
92  DISALLOW_COPY_AND_ASSIGN(TestDelegate);
93};
94
95}  // namespace
96
97class DriveURLRequestJobTest : public testing::Test {
98 protected:
99  DriveURLRequestJobTest()
100      : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {
101  }
102
103  virtual ~DriveURLRequestJobTest() {
104  }
105
106  virtual void SetUp() OVERRIDE {
107    // Initialize FakeDriveService.
108    fake_drive_service_.reset(new FakeDriveService);
109    ASSERT_TRUE(fake_drive_service_->LoadResourceListForWapi(
110        "gdata/root_feed.json"));
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
184TEST_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
198TEST_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
249TEST_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_EQ(GURL("https://3_document_alternate_link"),
265            test_delegate_->redirect_url());
266}
267
268TEST_F(DriveURLRequestJobTest, RootDirectory) {
269  net::URLRequest request(GURL("drive:drive/root"),
270                          net::DEFAULT_PRIORITY,
271                          test_delegate_.get(),
272                          url_request_context_.get());
273  request.Start();
274
275  base::RunLoop().Run();
276
277  EXPECT_EQ(net::URLRequestStatus::FAILED, request.status().status());
278  EXPECT_EQ(net::ERR_FAILED, request.status().error());
279}
280
281TEST_F(DriveURLRequestJobTest, Directory) {
282  net::URLRequest request(GURL("drive:drive/root/Directory 1"),
283                          net::DEFAULT_PRIORITY,
284                          test_delegate_.get(),
285                          url_request_context_.get());
286  request.Start();
287
288  base::RunLoop().Run();
289
290  EXPECT_EQ(net::URLRequestStatus::FAILED, request.status().status());
291  EXPECT_EQ(net::ERR_FAILED, request.status().error());
292}
293
294TEST_F(DriveURLRequestJobTest, NonExistingFile) {
295  net::URLRequest request(GURL("drive:drive/root/non-existing-file.txt"),
296                          net::DEFAULT_PRIORITY,
297                          test_delegate_.get(),
298                          url_request_context_.get());
299  request.Start();
300
301  base::RunLoop().Run();
302
303  EXPECT_EQ(net::URLRequestStatus::FAILED, request.status().status());
304  EXPECT_EQ(net::ERR_FILE_NOT_FOUND, request.status().error());
305}
306
307TEST_F(DriveURLRequestJobTest, WrongFormat) {
308  net::URLRequest request(GURL("drive:"),
309                          net::DEFAULT_PRIORITY,
310                          test_delegate_.get(),
311                          url_request_context_.get());
312  request.Start();
313
314  base::RunLoop().Run();
315
316  EXPECT_EQ(net::URLRequestStatus::FAILED, request.status().status());
317  EXPECT_EQ(net::ERR_INVALID_URL, request.status().error());
318}
319
320TEST_F(DriveURLRequestJobTest, Cancel) {
321  net::URLRequest request(GURL("drive:drive/root/File 1.txt"),
322                          net::DEFAULT_PRIORITY,
323                          test_delegate_.get(),
324                          url_request_context_.get());
325
326  // Start the request, and cancel it immediately after it.
327  request.Start();
328  request.Cancel();
329
330  base::RunLoop().Run();
331
332  EXPECT_EQ(net::URLRequestStatus::CANCELED, request.status().status());
333}
334
335TEST_F(DriveURLRequestJobTest, RangeHeader) {
336  const GURL kTestUrl("drive:drive/root/File 1.txt");
337  const base::FilePath kTestFilePath("drive/root/File 1.txt");
338
339  net::URLRequest request(kTestUrl,
340                          net::DEFAULT_PRIORITY,
341                          test_delegate_.get(),
342                          url_request_context_.get());
343
344  // Set range header.
345  request.SetExtraRequestHeaderByName(
346      "Range", "bytes=3-5", false /* overwrite */);
347  request.Start();
348
349  base::RunLoop().Run();
350
351  EXPECT_EQ(net::URLRequestStatus::SUCCESS, request.status().status());
352
353  // Reading file must be done after |request| runs, otherwise
354  // it'll create a local cache file, and we cannot test correctly.
355  std::string expected_data;
356  ASSERT_TRUE(ReadDriveFileSync(kTestFilePath, &expected_data));
357  EXPECT_EQ(expected_data.substr(3, 3), test_delegate_->data_received());
358}
359
360TEST_F(DriveURLRequestJobTest, WrongRangeHeader) {
361  const GURL kTestUrl("drive:drive/root/File 1.txt");
362
363  net::URLRequest request(kTestUrl,
364                          net::DEFAULT_PRIORITY,
365                          test_delegate_.get(),
366                          url_request_context_.get());
367
368  // Set range header.
369  request.SetExtraRequestHeaderByName(
370      "Range", "Wrong Range Header Value", false /* overwrite */);
371  request.Start();
372
373  base::RunLoop().Run();
374
375  EXPECT_EQ(net::URLRequestStatus::FAILED, request.status().status());
376  EXPECT_EQ(net::ERR_REQUEST_RANGE_NOT_SATISFIABLE, request.status().error());
377}
378
379}  // namespace drive
380