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