NaCl: Update revision in DEPS, r12770 -> r12773
[chromium-blink-merge.git] / chrome / browser / drive / drive_uploader_unittest.cc
blobccbbc971aa1e5a758ec1c8ad52c958fed33a3df2
1 // Copyright (c) 2012 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.
5 #include "chrome/browser/drive/drive_uploader.h"
7 #include <string>
8 #include <vector>
10 #include "base/bind.h"
11 #include "base/files/scoped_temp_dir.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/run_loop.h"
15 #include "base/values.h"
16 #include "chrome/browser/drive/dummy_drive_service.h"
17 #include "content/public/test/test_browser_thread_bundle.h"
18 #include "google_apis/drive/test_util.h"
19 #include "testing/gtest/include/gtest/gtest.h"
21 using google_apis::CancelCallback;
22 using google_apis::GDataErrorCode;
23 using google_apis::GDATA_NO_CONNECTION;
24 using google_apis::GDATA_OTHER_ERROR;
25 using google_apis::HTTP_CONFLICT;
26 using google_apis::HTTP_CREATED;
27 using google_apis::HTTP_NOT_FOUND;
28 using google_apis::HTTP_PRECONDITION;
29 using google_apis::HTTP_RESUME_INCOMPLETE;
30 using google_apis::HTTP_SUCCESS;
31 using google_apis::InitiateUploadCallback;
32 using google_apis::ProgressCallback;
33 using google_apis::ResourceEntry;
34 using google_apis::UploadRangeCallback;
35 using google_apis::UploadRangeResponse;
36 namespace test_util = google_apis::test_util;
38 namespace drive {
40 namespace {
42 const char kTestDummyId[] = "file:dummy_id";
43 const char kTestDocumentTitle[] = "Hello world";
44 const char kTestInitiateUploadParentResourceId[] = "parent_resource_id";
45 const char kTestInitiateUploadResourceId[] = "resource_id";
46 const char kTestMimeType[] = "text/plain";
47 const char kTestUploadNewFileURL[] = "http://test/upload_location/new_file";
48 const char kTestUploadExistingFileURL[] =
49 "http://test/upload_location/existing_file";
50 const int64 kUploadChunkSize = 512 * 1024;
51 const char kTestETag[] = "test_etag";
53 // Mock DriveService that verifies if the uploaded content matches the preset
54 // expectation.
55 class MockDriveServiceWithUploadExpectation : public DummyDriveService {
56 public:
57 // Sets up an expected upload content. InitiateUpload and ResumeUpload will
58 // verify that the specified data is correctly uploaded.
59 MockDriveServiceWithUploadExpectation(
60 const base::FilePath& expected_upload_file,
61 int64 expected_content_length)
62 : expected_upload_file_(expected_upload_file),
63 expected_content_length_(expected_content_length),
64 received_bytes_(0),
65 resume_upload_call_count_(0) {}
67 int64 received_bytes() const { return received_bytes_; }
68 void set_received_bytes(int64 received_bytes) {
69 received_bytes_ = received_bytes;
72 int64 resume_upload_call_count() const { return resume_upload_call_count_; }
74 private:
75 // DriveServiceInterface overrides.
76 // Handles a request for obtaining an upload location URL.
77 virtual CancelCallback InitiateUploadNewFile(
78 const std::string& content_type,
79 int64 content_length,
80 const std::string& parent_resource_id,
81 const std::string& title,
82 const InitiateUploadNewFileOptions& options,
83 const InitiateUploadCallback& callback) OVERRIDE {
84 EXPECT_EQ(kTestDocumentTitle, title);
85 EXPECT_EQ(kTestMimeType, content_type);
86 EXPECT_EQ(expected_content_length_, content_length);
87 EXPECT_EQ(kTestInitiateUploadParentResourceId, parent_resource_id);
89 // Calls back the upload URL for subsequent ResumeUpload requests.
90 // InitiateUpload is an asynchronous function, so don't callback directly.
91 base::MessageLoop::current()->PostTask(FROM_HERE,
92 base::Bind(callback, HTTP_SUCCESS, GURL(kTestUploadNewFileURL)));
93 return CancelCallback();
96 virtual CancelCallback InitiateUploadExistingFile(
97 const std::string& content_type,
98 int64 content_length,
99 const std::string& resource_id,
100 const InitiateUploadExistingFileOptions& options,
101 const InitiateUploadCallback& callback) OVERRIDE {
102 EXPECT_EQ(kTestMimeType, content_type);
103 EXPECT_EQ(expected_content_length_, content_length);
104 EXPECT_EQ(kTestInitiateUploadResourceId, resource_id);
106 if (!options.etag.empty() && options.etag != kTestETag) {
107 base::MessageLoop::current()->PostTask(FROM_HERE,
108 base::Bind(callback, HTTP_PRECONDITION, GURL()));
109 return CancelCallback();
112 // Calls back the upload URL for subsequent ResumeUpload requests.
113 // InitiateUpload is an asynchronous function, so don't callback directly.
114 base::MessageLoop::current()->PostTask(FROM_HERE,
115 base::Bind(callback, HTTP_SUCCESS, GURL(kTestUploadExistingFileURL)));
116 return CancelCallback();
119 // Handles a request for uploading a chunk of bytes.
120 virtual CancelCallback ResumeUpload(
121 const GURL& upload_location,
122 int64 start_position,
123 int64 end_position,
124 int64 content_length,
125 const std::string& content_type,
126 const base::FilePath& local_file_path,
127 const UploadRangeCallback& callback,
128 const ProgressCallback& progress_callback) OVERRIDE {
129 // The upload range should start from the current first unreceived byte.
130 EXPECT_EQ(received_bytes_, start_position);
131 EXPECT_EQ(expected_upload_file_, local_file_path);
133 // The upload data must be split into 512KB chunks.
134 const int64 expected_chunk_end =
135 std::min(received_bytes_ + kUploadChunkSize, expected_content_length_);
136 EXPECT_EQ(expected_chunk_end, end_position);
138 // The upload URL returned by InitiateUpload() must be used.
139 EXPECT_TRUE(GURL(kTestUploadNewFileURL) == upload_location ||
140 GURL(kTestUploadExistingFileURL) == upload_location);
142 // Other parameters should be the exact values passed to DriveUploader.
143 EXPECT_EQ(expected_content_length_, content_length);
144 EXPECT_EQ(kTestMimeType, content_type);
146 // Update the internal status of the current upload session.
147 resume_upload_call_count_++;
148 received_bytes_ = end_position;
150 // Callback progress
151 if (!progress_callback.is_null()) {
152 // For the testing purpose, it always notifies the progress at the end of
153 // each chunk uploading.
154 int64 chunk_size = end_position - start_position;
155 base::MessageLoop::current()->PostTask(FROM_HERE,
156 base::Bind(progress_callback, chunk_size, chunk_size));
159 SendUploadRangeResponse(upload_location, callback);
160 return CancelCallback();
163 // Handles a request to fetch the current upload status.
164 virtual CancelCallback GetUploadStatus(
165 const GURL& upload_location,
166 int64 content_length,
167 const UploadRangeCallback& callback) OVERRIDE {
168 EXPECT_EQ(expected_content_length_, content_length);
169 // The upload URL returned by InitiateUpload() must be used.
170 EXPECT_TRUE(GURL(kTestUploadNewFileURL) == upload_location ||
171 GURL(kTestUploadExistingFileURL) == upload_location);
173 SendUploadRangeResponse(upload_location, callback);
174 return CancelCallback();
177 // Runs |callback| with the current upload status.
178 void SendUploadRangeResponse(const GURL& upload_location,
179 const UploadRangeCallback& callback) {
180 // Callback with response.
181 UploadRangeResponse response;
182 scoped_ptr<ResourceEntry> entry;
183 if (received_bytes_ == expected_content_length_) {
184 GDataErrorCode response_code =
185 upload_location == GURL(kTestUploadNewFileURL) ?
186 HTTP_CREATED : HTTP_SUCCESS;
187 response = UploadRangeResponse(response_code, -1, -1);
189 base::DictionaryValue dict;
190 dict.Set("id.$t", new base::StringValue(kTestDummyId));
191 entry = ResourceEntry::CreateFrom(dict);
192 } else {
193 response = UploadRangeResponse(
194 HTTP_RESUME_INCOMPLETE, 0, received_bytes_);
196 // ResumeUpload is an asynchronous function, so don't callback directly.
197 base::MessageLoop::current()->PostTask(FROM_HERE,
198 base::Bind(callback, response, base::Passed(&entry)));
201 const base::FilePath expected_upload_file_;
202 const int64 expected_content_length_;
203 int64 received_bytes_;
204 int64 resume_upload_call_count_;
207 // Mock DriveService that returns a failure at InitiateUpload().
208 class MockDriveServiceNoConnectionAtInitiate : public DummyDriveService {
209 // Returns error.
210 virtual CancelCallback InitiateUploadNewFile(
211 const std::string& content_type,
212 int64 content_length,
213 const std::string& parent_resource_id,
214 const std::string& title,
215 const InitiateUploadNewFileOptions& options,
216 const InitiateUploadCallback& callback) OVERRIDE {
217 base::MessageLoop::current()->PostTask(FROM_HERE,
218 base::Bind(callback, GDATA_NO_CONNECTION, GURL()));
219 return CancelCallback();
222 virtual CancelCallback InitiateUploadExistingFile(
223 const std::string& content_type,
224 int64 content_length,
225 const std::string& resource_id,
226 const InitiateUploadExistingFileOptions& options,
227 const InitiateUploadCallback& callback) OVERRIDE {
228 base::MessageLoop::current()->PostTask(FROM_HERE,
229 base::Bind(callback, GDATA_NO_CONNECTION, GURL()));
230 return CancelCallback();
233 // Should not be used.
234 virtual CancelCallback ResumeUpload(
235 const GURL& upload_url,
236 int64 start_position,
237 int64 end_position,
238 int64 content_length,
239 const std::string& content_type,
240 const base::FilePath& local_file_path,
241 const UploadRangeCallback& callback,
242 const ProgressCallback& progress_callback) OVERRIDE {
243 NOTREACHED();
244 return CancelCallback();
248 // Mock DriveService that returns a failure at ResumeUpload().
249 class MockDriveServiceNoConnectionAtResume : public DummyDriveService {
250 // Succeeds and returns an upload location URL.
251 virtual CancelCallback InitiateUploadNewFile(
252 const std::string& content_type,
253 int64 content_length,
254 const std::string& parent_resource_id,
255 const std::string& title,
256 const InitiateUploadNewFileOptions& options,
257 const InitiateUploadCallback& callback) OVERRIDE {
258 base::MessageLoop::current()->PostTask(FROM_HERE,
259 base::Bind(callback, HTTP_SUCCESS, GURL(kTestUploadNewFileURL)));
260 return CancelCallback();
263 virtual CancelCallback InitiateUploadExistingFile(
264 const std::string& content_type,
265 int64 content_length,
266 const std::string& resource_id,
267 const InitiateUploadExistingFileOptions& options,
268 const InitiateUploadCallback& callback) OVERRIDE {
269 base::MessageLoop::current()->PostTask(FROM_HERE,
270 base::Bind(callback, HTTP_SUCCESS, GURL(kTestUploadExistingFileURL)));
271 return CancelCallback();
274 // Returns error.
275 virtual CancelCallback ResumeUpload(
276 const GURL& upload_url,
277 int64 start_position,
278 int64 end_position,
279 int64 content_length,
280 const std::string& content_type,
281 const base::FilePath& local_file_path,
282 const UploadRangeCallback& callback,
283 const ProgressCallback& progress_callback) OVERRIDE {
284 base::MessageLoop::current()->PostTask(FROM_HERE,
285 base::Bind(callback,
286 UploadRangeResponse(GDATA_NO_CONNECTION, -1, -1),
287 base::Passed(scoped_ptr<ResourceEntry>())));
288 return CancelCallback();
292 // Mock DriveService that returns a failure at GetUploadStatus().
293 class MockDriveServiceNoConnectionAtGetUploadStatus : public DummyDriveService {
294 // Returns error.
295 virtual CancelCallback GetUploadStatus(
296 const GURL& upload_url,
297 int64 content_length,
298 const UploadRangeCallback& callback) OVERRIDE {
299 base::MessageLoop::current()->PostTask(FROM_HERE,
300 base::Bind(callback,
301 UploadRangeResponse(GDATA_NO_CONNECTION, -1, -1),
302 base::Passed(scoped_ptr<ResourceEntry>())));
303 return CancelCallback();
307 class DriveUploaderTest : public testing::Test {
308 public:
309 virtual void SetUp() OVERRIDE {
310 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
313 protected:
314 content::TestBrowserThreadBundle thread_bundle_;
315 base::ScopedTempDir temp_dir_;
318 } // namespace
320 TEST_F(DriveUploaderTest, UploadExisting0KB) {
321 base::FilePath local_path;
322 std::string data;
323 ASSERT_TRUE(test_util::CreateFileOfSpecifiedSize(
324 temp_dir_.path(), 0, &local_path, &data));
326 GDataErrorCode error = GDATA_OTHER_ERROR;
327 GURL upload_location;
328 scoped_ptr<ResourceEntry> resource_entry;
330 MockDriveServiceWithUploadExpectation mock_service(local_path, data.size());
331 DriveUploader uploader(&mock_service,
332 base::MessageLoopProxy::current().get());
333 std::vector<test_util::ProgressInfo> upload_progress_values;
334 uploader.UploadExistingFile(
335 kTestInitiateUploadResourceId,
336 local_path,
337 kTestMimeType,
338 DriveUploader::UploadExistingFileOptions(),
339 test_util::CreateCopyResultCallback(
340 &error, &upload_location, &resource_entry),
341 base::Bind(&test_util::AppendProgressCallbackResult,
342 &upload_progress_values));
343 base::RunLoop().RunUntilIdle();
345 EXPECT_EQ(1, mock_service.resume_upload_call_count());
346 EXPECT_EQ(0, mock_service.received_bytes());
347 EXPECT_EQ(HTTP_SUCCESS, error);
348 EXPECT_TRUE(upload_location.is_empty());
349 ASSERT_TRUE(resource_entry);
350 EXPECT_EQ(kTestDummyId, resource_entry->id());
351 ASSERT_EQ(1U, upload_progress_values.size());
352 EXPECT_EQ(test_util::ProgressInfo(0, 0), upload_progress_values[0]);
355 TEST_F(DriveUploaderTest, UploadExisting512KB) {
356 base::FilePath local_path;
357 std::string data;
358 ASSERT_TRUE(test_util::CreateFileOfSpecifiedSize(
359 temp_dir_.path(), 512 * 1024, &local_path, &data));
361 GDataErrorCode error = GDATA_OTHER_ERROR;
362 GURL upload_location;
363 scoped_ptr<ResourceEntry> resource_entry;
365 MockDriveServiceWithUploadExpectation mock_service(local_path, data.size());
366 DriveUploader uploader(&mock_service,
367 base::MessageLoopProxy::current().get());
368 std::vector<test_util::ProgressInfo> upload_progress_values;
369 uploader.UploadExistingFile(
370 kTestInitiateUploadResourceId,
371 local_path,
372 kTestMimeType,
373 DriveUploader::UploadExistingFileOptions(),
374 test_util::CreateCopyResultCallback(
375 &error, &upload_location, &resource_entry),
376 base::Bind(&test_util::AppendProgressCallbackResult,
377 &upload_progress_values));
378 base::RunLoop().RunUntilIdle();
380 // 512KB upload should not be split into multiple chunks.
381 EXPECT_EQ(1, mock_service.resume_upload_call_count());
382 EXPECT_EQ(512 * 1024, mock_service.received_bytes());
383 EXPECT_EQ(HTTP_SUCCESS, error);
384 EXPECT_TRUE(upload_location.is_empty());
385 ASSERT_TRUE(resource_entry);
386 EXPECT_EQ(kTestDummyId, resource_entry->id());
387 ASSERT_EQ(1U, upload_progress_values.size());
388 EXPECT_EQ(test_util::ProgressInfo(512 * 1024, 512 * 1024),
389 upload_progress_values[0]);
392 TEST_F(DriveUploaderTest, InitiateUploadFail) {
393 base::FilePath local_path;
394 std::string data;
395 ASSERT_TRUE(test_util::CreateFileOfSpecifiedSize(
396 temp_dir_.path(), 512 * 1024, &local_path, &data));
398 GDataErrorCode error = HTTP_SUCCESS;
399 GURL upload_location;
400 scoped_ptr<ResourceEntry> resource_entry;
402 MockDriveServiceNoConnectionAtInitiate mock_service;
403 DriveUploader uploader(&mock_service,
404 base::MessageLoopProxy::current().get());
405 uploader.UploadExistingFile(kTestInitiateUploadResourceId,
406 local_path,
407 kTestMimeType,
408 DriveUploader::UploadExistingFileOptions(),
409 test_util::CreateCopyResultCallback(
410 &error, &upload_location, &resource_entry),
411 google_apis::ProgressCallback());
412 base::RunLoop().RunUntilIdle();
414 EXPECT_EQ(GDATA_NO_CONNECTION, error);
415 EXPECT_TRUE(upload_location.is_empty());
416 EXPECT_FALSE(resource_entry);
419 TEST_F(DriveUploaderTest, InitiateUploadNoConflict) {
420 base::FilePath local_path;
421 std::string data;
422 ASSERT_TRUE(test_util::CreateFileOfSpecifiedSize(
423 temp_dir_.path(), 512 * 1024, &local_path, &data));
425 GDataErrorCode error = GDATA_OTHER_ERROR;
426 GURL upload_location;
427 scoped_ptr<ResourceEntry> resource_entry;
429 MockDriveServiceWithUploadExpectation mock_service(local_path, data.size());
430 DriveUploader uploader(&mock_service,
431 base::MessageLoopProxy::current().get());
432 DriveUploader::UploadExistingFileOptions options;
433 options.etag = kTestETag;
434 uploader.UploadExistingFile(kTestInitiateUploadResourceId,
435 local_path,
436 kTestMimeType,
437 options,
438 test_util::CreateCopyResultCallback(
439 &error, &upload_location, &resource_entry),
440 google_apis::ProgressCallback());
441 base::RunLoop().RunUntilIdle();
443 EXPECT_EQ(HTTP_SUCCESS, error);
444 EXPECT_TRUE(upload_location.is_empty());
447 TEST_F(DriveUploaderTest, InitiateUploadConflict) {
448 base::FilePath local_path;
449 std::string data;
450 ASSERT_TRUE(test_util::CreateFileOfSpecifiedSize(
451 temp_dir_.path(), 512 * 1024, &local_path, &data));
452 const std::string kDestinationETag("destination_etag");
454 GDataErrorCode error = GDATA_OTHER_ERROR;
455 GURL upload_location;
456 scoped_ptr<ResourceEntry> resource_entry;
458 MockDriveServiceWithUploadExpectation mock_service(local_path, data.size());
459 DriveUploader uploader(&mock_service,
460 base::MessageLoopProxy::current().get());
461 DriveUploader::UploadExistingFileOptions options;
462 options.etag = kDestinationETag;
463 uploader.UploadExistingFile(kTestInitiateUploadResourceId,
464 local_path,
465 kTestMimeType,
466 options,
467 test_util::CreateCopyResultCallback(
468 &error, &upload_location, &resource_entry),
469 google_apis::ProgressCallback());
470 base::RunLoop().RunUntilIdle();
472 EXPECT_EQ(HTTP_CONFLICT, error);
473 EXPECT_TRUE(upload_location.is_empty());
476 TEST_F(DriveUploaderTest, ResumeUploadFail) {
477 base::FilePath local_path;
478 std::string data;
479 ASSERT_TRUE(test_util::CreateFileOfSpecifiedSize(
480 temp_dir_.path(), 512 * 1024, &local_path, &data));
482 GDataErrorCode error = HTTP_SUCCESS;
483 GURL upload_location;
484 scoped_ptr<ResourceEntry> resource_entry;
486 MockDriveServiceNoConnectionAtResume mock_service;
487 DriveUploader uploader(&mock_service,
488 base::MessageLoopProxy::current().get());
489 uploader.UploadExistingFile(kTestInitiateUploadResourceId,
490 local_path,
491 kTestMimeType,
492 DriveUploader::UploadExistingFileOptions(),
493 test_util::CreateCopyResultCallback(
494 &error, &upload_location, &resource_entry),
495 google_apis::ProgressCallback());
496 base::RunLoop().RunUntilIdle();
498 EXPECT_EQ(GDATA_NO_CONNECTION, error);
499 EXPECT_EQ(GURL(kTestUploadExistingFileURL), upload_location);
502 TEST_F(DriveUploaderTest, GetUploadStatusFail) {
503 base::FilePath local_path;
504 std::string data;
505 ASSERT_TRUE(test_util::CreateFileOfSpecifiedSize(
506 temp_dir_.path(), 512 * 1024, &local_path, &data));
508 GDataErrorCode error = HTTP_SUCCESS;
509 GURL upload_location;
510 scoped_ptr<ResourceEntry> resource_entry;
512 MockDriveServiceNoConnectionAtGetUploadStatus mock_service;
513 DriveUploader uploader(&mock_service,
514 base::MessageLoopProxy::current().get());
515 uploader.ResumeUploadFile(GURL(kTestUploadExistingFileURL),
516 local_path,
517 kTestMimeType,
518 test_util::CreateCopyResultCallback(
519 &error, &upload_location, &resource_entry),
520 google_apis::ProgressCallback());
521 base::RunLoop().RunUntilIdle();
523 EXPECT_EQ(GDATA_NO_CONNECTION, error);
524 EXPECT_TRUE(upload_location.is_empty());
527 TEST_F(DriveUploaderTest, NonExistingSourceFile) {
528 GDataErrorCode error = GDATA_OTHER_ERROR;
529 GURL upload_location;
530 scoped_ptr<ResourceEntry> resource_entry;
532 DriveUploader uploader(NULL, // NULL, the service won't be used.
533 base::MessageLoopProxy::current().get());
534 uploader.UploadExistingFile(
535 kTestInitiateUploadResourceId,
536 temp_dir_.path().AppendASCII("_this_path_should_not_exist_"),
537 kTestMimeType,
538 DriveUploader::UploadExistingFileOptions(),
539 test_util::CreateCopyResultCallback(
540 &error, &upload_location, &resource_entry),
541 google_apis::ProgressCallback());
542 base::RunLoop().RunUntilIdle();
544 // Should return failure without doing any attempt to connect to the server.
545 EXPECT_EQ(HTTP_NOT_FOUND, error);
546 EXPECT_TRUE(upload_location.is_empty());
549 TEST_F(DriveUploaderTest, ResumeUpload) {
550 base::FilePath local_path;
551 std::string data;
552 ASSERT_TRUE(test_util::CreateFileOfSpecifiedSize(
553 temp_dir_.path(), 1024 * 1024, &local_path, &data));
555 GDataErrorCode error = GDATA_OTHER_ERROR;
556 GURL upload_location;
557 scoped_ptr<ResourceEntry> resource_entry;
559 MockDriveServiceWithUploadExpectation mock_service(local_path, data.size());
560 DriveUploader uploader(&mock_service,
561 base::MessageLoopProxy::current().get());
562 // Emulate the situation that the only first part is successfully uploaded,
563 // but not the latter half.
564 mock_service.set_received_bytes(512 * 1024);
566 std::vector<test_util::ProgressInfo> upload_progress_values;
567 uploader.ResumeUploadFile(
568 GURL(kTestUploadExistingFileURL),
569 local_path,
570 kTestMimeType,
571 test_util::CreateCopyResultCallback(
572 &error, &upload_location, &resource_entry),
573 base::Bind(&test_util::AppendProgressCallbackResult,
574 &upload_progress_values));
575 base::RunLoop().RunUntilIdle();
577 EXPECT_EQ(1, mock_service.resume_upload_call_count());
578 EXPECT_EQ(1024 * 1024, mock_service.received_bytes());
579 EXPECT_EQ(HTTP_SUCCESS, error);
580 EXPECT_TRUE(upload_location.is_empty());
581 ASSERT_TRUE(resource_entry);
582 EXPECT_EQ(kTestDummyId, resource_entry->id());
583 ASSERT_EQ(1U, upload_progress_values.size());
584 EXPECT_EQ(test_util::ProgressInfo(1024 * 1024, 1024 * 1024),
585 upload_progress_values[0]);
588 } // namespace drive