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