OLD | NEW |
| (Empty) |
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/files/file_util.h" | |
9 #include "base/memory/ref_counted.h" | |
10 #include "base/memory/scoped_ptr.h" | |
11 #include "base/run_loop.h" | |
12 #include "base/threading/thread.h" | |
13 #include "chrome/browser/chromeos/drive/drive_file_stream_reader.h" | |
14 #include "chrome/browser/chromeos/drive/drive_integration_service.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/browser/prefs/browser_prefs.h" | |
21 #include "chrome/browser/prefs/pref_service_syncable.h" | |
22 #include "chrome/browser/profiles/profile_manager.h" | |
23 #include "chrome/common/url_constants.h" | |
24 #include "chrome/test/base/testing_browser_process.h" | |
25 #include "chrome/test/base/testing_profile.h" | |
26 #include "chrome/test/base/testing_profile_manager.h" | |
27 #include "components/pref_registry/pref_registry_syncable.h" | |
28 #include "components/pref_registry/testing_pref_service_syncable.h" | |
29 #include "content/public/browser/browser_thread.h" | |
30 #include "content/public/test/test_browser_thread_bundle.h" | |
31 #include "content/public/test/test_file_system_options.h" | |
32 #include "google_apis/drive/test_util.h" | |
33 #include "net/base/request_priority.h" | |
34 #include "net/base/test_completion_callback.h" | |
35 #include "net/http/http_byte_range.h" | |
36 #include "net/url_request/redirect_info.h" | |
37 #include "net/url_request/url_request.h" | |
38 #include "net/url_request/url_request_context.h" | |
39 #include "net/url_request/url_request_test_util.h" | |
40 #include "storage/browser/fileapi/external_mount_points.h" | |
41 #include "storage/browser/fileapi/file_system_context.h" | |
42 #include "testing/gtest/include/gtest/gtest.h" | |
43 #include "url/gurl.h" | |
44 | |
45 namespace drive { | |
46 namespace { | |
47 | |
48 // A simple URLRequestJobFactory implementation to create DriveURLRequestJob. | |
49 class TestURLRequestJobFactory : public net::URLRequestJobFactory { | |
50 public: | |
51 explicit TestURLRequestJobFactory(void* profile_id) | |
52 : profile_id_(profile_id) {} | |
53 | |
54 virtual ~TestURLRequestJobFactory() {} | |
55 | |
56 // net::URLRequestJobFactory override: | |
57 virtual net::URLRequestJob* MaybeCreateJobWithProtocolHandler( | |
58 const std::string& scheme, | |
59 net::URLRequest* request, | |
60 net::NetworkDelegate* network_delegate) const OVERRIDE { | |
61 return new DriveURLRequestJob(profile_id_, request, network_delegate); | |
62 } | |
63 | |
64 virtual bool IsHandledProtocol(const std::string& scheme) const OVERRIDE { | |
65 return scheme == chrome::kDriveScheme; | |
66 } | |
67 | |
68 virtual bool IsHandledURL(const GURL& url) const OVERRIDE { | |
69 return url.is_valid() && IsHandledProtocol(url.scheme()); | |
70 } | |
71 | |
72 virtual bool IsSafeRedirectTarget(const GURL& location) const OVERRIDE { | |
73 return true; | |
74 } | |
75 | |
76 private: | |
77 void* const profile_id_; | |
78 DISALLOW_COPY_AND_ASSIGN(TestURLRequestJobFactory); | |
79 }; | |
80 | |
81 class TestDelegate : public net::TestDelegate { | |
82 public: | |
83 TestDelegate() {} | |
84 | |
85 const GURL& redirect_url() const { return redirect_url_; } | |
86 | |
87 // net::TestDelegate override. | |
88 virtual void OnReceivedRedirect(net::URLRequest* request, | |
89 const net::RedirectInfo& redirect_info, | |
90 bool* defer_redirect) OVERRIDE { | |
91 redirect_url_ = redirect_info.new_url; | |
92 net::TestDelegate::OnReceivedRedirect( | |
93 request, redirect_info, defer_redirect); | |
94 } | |
95 | |
96 private: | |
97 GURL redirect_url_; | |
98 | |
99 DISALLOW_COPY_AND_ASSIGN(TestDelegate); | |
100 }; | |
101 | |
102 } // namespace | |
103 | |
104 class DriveURLRequestJobTest : public testing::Test { | |
105 protected: | |
106 DriveURLRequestJobTest() | |
107 : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP), | |
108 integration_service_factory_callback_( | |
109 base::Bind(&DriveURLRequestJobTest::CreateDriveIntegrationService, | |
110 base::Unretained(this))), | |
111 fake_file_system_(NULL) {} | |
112 | |
113 virtual ~DriveURLRequestJobTest() { | |
114 } | |
115 | |
116 virtual void SetUp() OVERRIDE { | |
117 // Create a testing profile. | |
118 profile_manager_.reset( | |
119 new TestingProfileManager(TestingBrowserProcess::GetGlobal())); | |
120 ASSERT_TRUE(profile_manager_->SetUp()); | |
121 Profile* const profile = | |
122 profile_manager_->CreateTestingProfile("test-user"); | |
123 | |
124 // Create the drive integration service for the profile. | |
125 integration_service_factory_scope_.reset( | |
126 new DriveIntegrationServiceFactory::ScopedFactoryForTest( | |
127 &integration_service_factory_callback_)); | |
128 DriveIntegrationServiceFactory::GetForProfile(profile); | |
129 | |
130 // Create the URL request job factory. | |
131 test_network_delegate_.reset(new net::TestNetworkDelegate); | |
132 test_url_request_job_factory_.reset(new TestURLRequestJobFactory(profile)); | |
133 url_request_context_.reset(new net::URLRequestContext()); | |
134 url_request_context_->set_job_factory(test_url_request_job_factory_.get()); | |
135 url_request_context_->set_network_delegate(test_network_delegate_.get()); | |
136 test_delegate_.reset(new TestDelegate); | |
137 } | |
138 | |
139 virtual void TearDown() { profile_manager_.reset(); } | |
140 | |
141 bool ReadDriveFileSync( | |
142 const base::FilePath& file_path, std::string* out_content) { | |
143 scoped_ptr<base::Thread> worker_thread( | |
144 new base::Thread("ReadDriveFileSync")); | |
145 if (!worker_thread->Start()) | |
146 return false; | |
147 | |
148 scoped_ptr<DriveFileStreamReader> reader(new DriveFileStreamReader( | |
149 base::Bind(&DriveURLRequestJobTest::GetFileSystem, | |
150 base::Unretained(this)), | |
151 worker_thread->message_loop_proxy().get())); | |
152 int error = net::ERR_FAILED; | |
153 scoped_ptr<ResourceEntry> entry; | |
154 { | |
155 base::RunLoop run_loop; | |
156 reader->Initialize( | |
157 file_path, | |
158 net::HttpByteRange(), | |
159 google_apis::test_util::CreateQuitCallback( | |
160 &run_loop, | |
161 google_apis::test_util::CreateCopyResultCallback( | |
162 &error, &entry))); | |
163 run_loop.Run(); | |
164 } | |
165 if (error != net::OK || !entry) | |
166 return false; | |
167 | |
168 // Read data from the reader. | |
169 std::string content; | |
170 if (test_util::ReadAllData(reader.get(), &content) != net::OK) | |
171 return false; | |
172 | |
173 if (static_cast<size_t>(entry->file_info().size()) != content.size()) | |
174 return false; | |
175 | |
176 *out_content = content; | |
177 return true; | |
178 } | |
179 | |
180 scoped_ptr<net::URLRequestContext> url_request_context_; | |
181 scoped_ptr<TestDelegate> test_delegate_; | |
182 | |
183 private: | |
184 // Create the drive integration service for the |profile| | |
185 DriveIntegrationService* CreateDriveIntegrationService(Profile* profile) { | |
186 FakeDriveService* const drive_service = new FakeDriveService; | |
187 if (!test_util::SetUpTestEntries(drive_service)) | |
188 return NULL; | |
189 | |
190 const std::string& drive_mount_name = | |
191 util::GetDriveMountPointPath(profile).BaseName().AsUTF8Unsafe(); | |
192 storage::ExternalMountPoints::GetSystemInstance()->RegisterFileSystem( | |
193 drive_mount_name, | |
194 storage::kFileSystemTypeDrive, | |
195 storage::FileSystemMountOption(), | |
196 util::GetDriveMountPointPath(profile)); | |
197 DCHECK(!fake_file_system_); | |
198 fake_file_system_ = new test_util::FakeFileSystem(drive_service); | |
199 if (!drive_cache_dir_.CreateUniqueTempDir()) | |
200 return NULL; | |
201 return new drive::DriveIntegrationService(profile, | |
202 NULL, | |
203 drive_service, | |
204 drive_mount_name, | |
205 drive_cache_dir_.path(), | |
206 fake_file_system_); | |
207 } | |
208 | |
209 FileSystemInterface* GetFileSystem() { return fake_file_system_; } | |
210 | |
211 content::TestBrowserThreadBundle thread_bundle_; | |
212 DriveIntegrationServiceFactory::FactoryCallback | |
213 integration_service_factory_callback_; | |
214 scoped_ptr<DriveIntegrationServiceFactory::ScopedFactoryForTest> | |
215 integration_service_factory_scope_; | |
216 scoped_ptr<DriveIntegrationService> integration_service_; | |
217 test_util::FakeFileSystem* fake_file_system_; | |
218 | |
219 scoped_ptr<net::TestNetworkDelegate> test_network_delegate_; | |
220 scoped_ptr<TestURLRequestJobFactory> test_url_request_job_factory_; | |
221 | |
222 scoped_ptr<TestingProfileManager> profile_manager_; | |
223 base::ScopedTempDir drive_cache_dir_; | |
224 scoped_refptr<storage::FileSystemContext> file_system_context_; | |
225 }; | |
226 | |
227 TEST_F(DriveURLRequestJobTest, NonGetMethod) { | |
228 scoped_ptr<net::URLRequest> request(url_request_context_->CreateRequest( | |
229 GURL("drive:drive/root/File 1.txt"), | |
230 net::DEFAULT_PRIORITY, | |
231 test_delegate_.get(), | |
232 NULL)); | |
233 request->set_method("POST"); // Set non "GET" method. | |
234 request->Start(); | |
235 | |
236 base::RunLoop().Run(); | |
237 | |
238 EXPECT_EQ(net::URLRequestStatus::FAILED, request->status().status()); | |
239 EXPECT_EQ(net::ERR_METHOD_NOT_SUPPORTED, request->status().error()); | |
240 } | |
241 | |
242 TEST_F(DriveURLRequestJobTest, RegularFile) { | |
243 const GURL kTestUrl("drive:drive/root/File 1.txt"); | |
244 const base::FilePath kTestFilePath("drive/root/File 1.txt"); | |
245 | |
246 // For the first time, the file should be fetched from the server. | |
247 { | |
248 scoped_ptr<net::URLRequest> request(url_request_context_->CreateRequest( | |
249 kTestUrl, | |
250 net::DEFAULT_PRIORITY, | |
251 test_delegate_.get(), | |
252 NULL)); | |
253 request->Start(); | |
254 | |
255 base::RunLoop().Run(); | |
256 | |
257 EXPECT_EQ(net::URLRequestStatus::SUCCESS, request->status().status()); | |
258 // It looks weird, but the mime type for the "File 1.txt" is "audio/mpeg" | |
259 // on the server. | |
260 std::string mime_type; | |
261 request->GetMimeType(&mime_type); | |
262 EXPECT_EQ("audio/mpeg", mime_type); | |
263 | |
264 // Reading file must be done after |request| runs, otherwise | |
265 // it'll create a local cache file, and we cannot test correctly. | |
266 std::string expected_data; | |
267 ASSERT_TRUE(ReadDriveFileSync(kTestFilePath, &expected_data)); | |
268 EXPECT_EQ(expected_data, test_delegate_->data_received()); | |
269 } | |
270 | |
271 // For the second time, the locally cached file should be used. | |
272 // The caching emulation is done by FakeFileSystem. | |
273 { | |
274 test_delegate_.reset(new TestDelegate); | |
275 scoped_ptr<net::URLRequest> request(url_request_context_->CreateRequest( | |
276 GURL("drive:drive/root/File 1.txt"), | |
277 net::DEFAULT_PRIORITY, | |
278 test_delegate_.get(), | |
279 NULL)); | |
280 request->Start(); | |
281 | |
282 base::RunLoop().Run(); | |
283 | |
284 EXPECT_EQ(net::URLRequestStatus::SUCCESS, request->status().status()); | |
285 std::string mime_type; | |
286 request->GetMimeType(&mime_type); | |
287 EXPECT_EQ("audio/mpeg", mime_type); | |
288 | |
289 std::string expected_data; | |
290 ASSERT_TRUE(ReadDriveFileSync(kTestFilePath, &expected_data)); | |
291 EXPECT_EQ(expected_data, test_delegate_->data_received()); | |
292 } | |
293 } | |
294 | |
295 TEST_F(DriveURLRequestJobTest, HostedDocument) { | |
296 // Open a gdoc file. | |
297 test_delegate_->set_quit_on_redirect(true); | |
298 scoped_ptr<net::URLRequest> request(url_request_context_->CreateRequest( | |
299 GURL("drive:drive/root/Document 1 excludeDir-test.gdoc"), | |
300 net::DEFAULT_PRIORITY, | |
301 test_delegate_.get(), | |
302 NULL)); | |
303 request->Start(); | |
304 | |
305 base::RunLoop().Run(); | |
306 | |
307 EXPECT_EQ(net::URLRequestStatus::SUCCESS, request->status().status()); | |
308 // Make sure that a hosted document triggers redirection. | |
309 EXPECT_TRUE(request->is_redirecting()); | |
310 EXPECT_TRUE(test_delegate_->redirect_url().is_valid()); | |
311 } | |
312 | |
313 TEST_F(DriveURLRequestJobTest, RootDirectory) { | |
314 scoped_ptr<net::URLRequest> request(url_request_context_->CreateRequest( | |
315 GURL("drive:drive/root"), | |
316 net::DEFAULT_PRIORITY, | |
317 test_delegate_.get(), | |
318 NULL)); | |
319 request->Start(); | |
320 | |
321 base::RunLoop().Run(); | |
322 | |
323 EXPECT_EQ(net::URLRequestStatus::FAILED, request->status().status()); | |
324 EXPECT_EQ(net::ERR_FAILED, request->status().error()); | |
325 } | |
326 | |
327 TEST_F(DriveURLRequestJobTest, Directory) { | |
328 scoped_ptr<net::URLRequest> request(url_request_context_->CreateRequest( | |
329 GURL("drive:drive/root/Directory 1"), | |
330 net::DEFAULT_PRIORITY, | |
331 test_delegate_.get(), | |
332 NULL)); | |
333 request->Start(); | |
334 | |
335 base::RunLoop().Run(); | |
336 | |
337 EXPECT_EQ(net::URLRequestStatus::FAILED, request->status().status()); | |
338 EXPECT_EQ(net::ERR_FAILED, request->status().error()); | |
339 } | |
340 | |
341 TEST_F(DriveURLRequestJobTest, NonExistingFile) { | |
342 scoped_ptr<net::URLRequest> request(url_request_context_->CreateRequest( | |
343 GURL("drive:drive/root/non-existing-file.txt"), | |
344 net::DEFAULT_PRIORITY, | |
345 test_delegate_.get(), | |
346 NULL)); | |
347 request->Start(); | |
348 | |
349 base::RunLoop().Run(); | |
350 | |
351 EXPECT_EQ(net::URLRequestStatus::FAILED, request->status().status()); | |
352 EXPECT_EQ(net::ERR_FILE_NOT_FOUND, request->status().error()); | |
353 } | |
354 | |
355 TEST_F(DriveURLRequestJobTest, WrongFormat) { | |
356 scoped_ptr<net::URLRequest> request(url_request_context_->CreateRequest( | |
357 GURL("drive:"), | |
358 net::DEFAULT_PRIORITY, | |
359 test_delegate_.get(), | |
360 NULL)); | |
361 request->Start(); | |
362 | |
363 base::RunLoop().Run(); | |
364 | |
365 EXPECT_EQ(net::URLRequestStatus::FAILED, request->status().status()); | |
366 EXPECT_EQ(net::ERR_INVALID_URL, request->status().error()); | |
367 } | |
368 | |
369 TEST_F(DriveURLRequestJobTest, Cancel) { | |
370 scoped_ptr<net::URLRequest> request(url_request_context_->CreateRequest( | |
371 GURL("drive:drive/root/File 1.txt"), | |
372 net::DEFAULT_PRIORITY, | |
373 test_delegate_.get(), | |
374 NULL)); | |
375 | |
376 // Start the request, and cancel it immediately after it. | |
377 request->Start(); | |
378 request->Cancel(); | |
379 | |
380 base::RunLoop().Run(); | |
381 | |
382 EXPECT_EQ(net::URLRequestStatus::CANCELED, request->status().status()); | |
383 } | |
384 | |
385 TEST_F(DriveURLRequestJobTest, RangeHeader) { | |
386 const GURL kTestUrl("drive:drive/root/File 1.txt"); | |
387 const base::FilePath kTestFilePath("drive/root/File 1.txt"); | |
388 | |
389 scoped_ptr<net::URLRequest> request(url_request_context_->CreateRequest( | |
390 kTestUrl, | |
391 net::DEFAULT_PRIORITY, | |
392 test_delegate_.get(), | |
393 NULL)); | |
394 | |
395 // Set range header. | |
396 request->SetExtraRequestHeaderByName( | |
397 "Range", "bytes=3-5", false /* overwrite */); | |
398 request->Start(); | |
399 | |
400 base::RunLoop().Run(); | |
401 | |
402 EXPECT_EQ(net::URLRequestStatus::SUCCESS, request->status().status()); | |
403 | |
404 // Reading file must be done after |request| runs, otherwise | |
405 // it'll create a local cache file, and we cannot test correctly. | |
406 std::string expected_data; | |
407 ASSERT_TRUE(ReadDriveFileSync(kTestFilePath, &expected_data)); | |
408 EXPECT_EQ(expected_data.substr(3, 3), test_delegate_->data_received()); | |
409 } | |
410 | |
411 TEST_F(DriveURLRequestJobTest, WrongRangeHeader) { | |
412 const GURL kTestUrl("drive:drive/root/File 1.txt"); | |
413 | |
414 scoped_ptr<net::URLRequest> request(url_request_context_->CreateRequest( | |
415 kTestUrl, | |
416 net::DEFAULT_PRIORITY, | |
417 test_delegate_.get(), | |
418 NULL)); | |
419 | |
420 // Set range header. | |
421 request->SetExtraRequestHeaderByName( | |
422 "Range", "Wrong Range Header Value", false /* overwrite */); | |
423 request->Start(); | |
424 | |
425 base::RunLoop().Run(); | |
426 | |
427 EXPECT_EQ(net::URLRequestStatus::FAILED, request->status().status()); | |
428 EXPECT_EQ(net::ERR_REQUEST_RANGE_NOT_SATISFIABLE, request->status().error()); | |
429 } | |
430 | |
431 } // namespace drive | |
OLD | NEW |