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