Fix build break
[chromium-blink-merge.git] / chrome / browser / google_apis / drive_uploader_unittest.cc
blob6b51b89f3d6074d926e41781b8842906504ff940
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/google_apis/drive_uploader.h"
7 #include <algorithm>
8 #include <cstdlib>
9 #include <string>
10 #include <utility>
11 #include <vector>
13 #include "base/bind.h"
14 #include "base/file_util.h"
15 #include "base/files/scoped_temp_dir.h"
16 #include "base/memory/scoped_ptr.h"
17 #include "base/message_loop.h"
18 #include "base/values.h"
19 #include "chrome/browser/google_apis/dummy_drive_service.h"
20 #include "chrome/browser/google_apis/test_util.h"
21 #include "content/public/test/test_browser_thread.h"
22 #include "net/base/io_buffer.h"
23 #include "testing/gtest/include/gtest/gtest.h"
25 namespace google_apis {
27 namespace {
29 const char kTestDummyId[] = "file:dummy_id";
30 const char kTestDocumentTitle[] = "Hello world";
31 const char kTestDrivePath[] = "drive/dummy.txt";
32 const char kTestInitiateUploadParentResourceId[] = "parent_resource_id";
33 const char kTestInitiateUploadResourceId[] = "resource_id";
34 const char kTestMimeType[] = "text/plain";
35 const char kTestUploadURL[] = "http://test/upload_location";
36 const int64 kUploadChunkSize = 512 * 1024;
37 const char kTestETag[] = "test_etag";
39 // Creates a |size| byte file and returns its |path|. The file is filled with
40 // random bytes so that the test assertions can identify correct
41 // portion of the file is being sent.
42 bool CreateFileOfSpecifiedSize(const base::FilePath& temp_dir,
43 size_t size,
44 base::FilePath* path,
45 std::string* data) {
46 data->resize(size);
47 for (size_t i = 0; i < size; ++i)
48 (*data)[i] = static_cast<char>(rand() % 256); // NOLINT
49 if (!file_util::CreateTemporaryFileInDir(temp_dir, path))
50 return false;
51 return file_util::WriteFile(*path, data->c_str(), static_cast<int>(size)) ==
52 static_cast<int>(size);
55 // Mock DriveService that verifies if the uploaded content matches the preset
56 // expectation.
57 class MockDriveServiceWithUploadExpectation : public DummyDriveService {
58 public:
59 // Sets up an expected upload content. InitiateUpload and ResumeUpload will
60 // verify that the specified data is correctly uploaded.
61 explicit MockDriveServiceWithUploadExpectation(
62 const std::string& expected_upload_content)
63 : expected_upload_content_(expected_upload_content),
64 received_bytes_(0),
65 resume_upload_call_count_(0) {}
67 int64 received_bytes() const { return received_bytes_; }
69 int64 resume_upload_call_count() const { return resume_upload_call_count_; }
71 private:
72 // DriveServiceInterface overrides.
73 // Handles a request for obtaining an upload location URL.
74 virtual void InitiateUploadNewFile(
75 const base::FilePath& drive_file_path,
76 const std::string& content_type,
77 int64 content_length,
78 const std::string& parent_resource_id,
79 const std::string& title,
80 const InitiateUploadCallback& callback) OVERRIDE {
81 EXPECT_EQ(kTestDocumentTitle, title);
82 EXPECT_EQ(kTestMimeType, content_type);
83 const int64 expected_size = expected_upload_content_.size();
84 EXPECT_EQ(expected_size, content_length);
85 EXPECT_EQ(kTestInitiateUploadParentResourceId, parent_resource_id);
87 // Calls back the upload URL for subsequent ResumeUpload operations.
88 // InitiateUpload is an asynchronous function, so don't callback directly.
89 MessageLoop::current()->PostTask(FROM_HERE,
90 base::Bind(callback, HTTP_SUCCESS, GURL(kTestUploadURL)));
93 virtual void InitiateUploadExistingFile(
94 const base::FilePath& drive_file_path,
95 const std::string& content_type,
96 int64 content_length,
97 const std::string& resource_id,
98 const std::string& etag,
99 const InitiateUploadCallback& callback) OVERRIDE {
100 EXPECT_EQ(kTestMimeType, content_type);
101 const int64 expected_size = expected_upload_content_.size();
102 EXPECT_EQ(expected_size, content_length);
103 EXPECT_EQ(kTestInitiateUploadResourceId, resource_id);
105 if (!etag.empty() && etag != kTestETag) {
106 MessageLoop::current()->PostTask(FROM_HERE,
107 base::Bind(callback, HTTP_PRECONDITION, GURL()));
108 return;
111 // Calls back the upload URL for subsequent ResumeUpload operations.
112 // InitiateUpload is an asynchronous function, so don't callback directly.
113 MessageLoop::current()->PostTask(FROM_HERE,
114 base::Bind(callback, HTTP_SUCCESS, GURL(kTestUploadURL)));
117 // Handles a request for uploading a chunk of bytes.
118 virtual void ResumeUpload(
119 UploadMode upload_mode,
120 const base::FilePath& drive_file_path,
121 const GURL& upload_url,
122 int64 start_position,
123 int64 end_position,
124 int64 content_length,
125 const std::string& content_type,
126 const scoped_refptr<net::IOBuffer>& buf,
127 const UploadRangeCallback& callback,
128 const ProgressCallback& progress_callback) OVERRIDE {
129 const int64 expected_size = expected_upload_content_.size();
131 // The upload range should start from the current first unreceived byte.
132 EXPECT_EQ(received_bytes_, start_position);
134 // The upload data must be split into 512KB chunks.
135 const int64 expected_chunk_end =
136 std::min(received_bytes_ + kUploadChunkSize, expected_size);
137 EXPECT_EQ(expected_chunk_end, end_position);
139 const int64 expected_chunk_size = expected_chunk_end - received_bytes_;
140 const std::string expected_chunk_data(
141 expected_upload_content_.substr(received_bytes_,
142 expected_chunk_size));
143 std::string uploading_data(buf->data(), buf->data() + expected_chunk_size);
144 EXPECT_EQ(expected_chunk_data, uploading_data);
146 // The upload URL returned by InitiateUpload() must be used.
147 EXPECT_EQ(GURL(kTestUploadURL), upload_url);
149 // Other parameters should be the exact values passed to DriveUploader.
150 EXPECT_EQ(expected_size, content_length);
151 EXPECT_EQ(kTestMimeType, content_type);
153 // Update the internal status of the current upload session.
154 resume_upload_call_count_++;
155 received_bytes_ = end_position;
157 // Callback progress
158 if (!progress_callback.is_null()) {
159 // For the testing purpose, it always notifies the progress at the end of
160 // each chunk uploading.
161 MessageLoop::current()->PostTask(FROM_HERE,
162 base::Bind(progress_callback, expected_chunk_size,
163 expected_chunk_size));
166 // Callback with response.
167 UploadRangeResponse response;
168 scoped_ptr<ResourceEntry> entry;
169 if (received_bytes_ == content_length) {
170 response = UploadRangeResponse(
171 upload_mode == UPLOAD_NEW_FILE ? HTTP_CREATED : HTTP_SUCCESS,
172 -1, -1);
174 base::DictionaryValue dict;
175 dict.Set("id.$t", new base::StringValue(kTestDummyId));
176 entry = ResourceEntry::CreateFrom(dict);
177 } else {
178 response = UploadRangeResponse(HTTP_RESUME_INCOMPLETE, 0, end_position);
180 // ResumeUpload is an asynchronous function, so don't callback directly.
181 MessageLoop::current()->PostTask(FROM_HERE,
182 base::Bind(callback, response, base::Passed(&entry)));
185 std::string expected_upload_content_;
186 int64 received_bytes_;
187 int64 resume_upload_call_count_;
190 // Mock DriveService that returns a failure at InitiateUpload().
191 class MockDriveServiceNoConnectionAtInitiate : public DummyDriveService {
192 // Returns error.
193 virtual void InitiateUploadNewFile(
194 const base::FilePath& drive_file_path,
195 const std::string& content_type,
196 int64 content_length,
197 const std::string& parent_resource_id,
198 const std::string& title,
199 const InitiateUploadCallback& callback) OVERRIDE {
200 MessageLoop::current()->PostTask(FROM_HERE,
201 base::Bind(callback, GDATA_NO_CONNECTION, GURL()));
204 virtual void InitiateUploadExistingFile(
205 const base::FilePath& drive_file_path,
206 const std::string& content_type,
207 int64 content_length,
208 const std::string& resource_id,
209 const std::string& etag,
210 const InitiateUploadCallback& callback) OVERRIDE {
211 MessageLoop::current()->PostTask(FROM_HERE,
212 base::Bind(callback, GDATA_NO_CONNECTION, GURL()));
215 // Should not be used.
216 virtual void ResumeUpload(
217 UploadMode upload_mode,
218 const base::FilePath& drive_file_path,
219 const GURL& upload_url,
220 int64 start_position,
221 int64 end_position,
222 int64 content_length,
223 const std::string& content_type,
224 const scoped_refptr<net::IOBuffer>& buf,
225 const UploadRangeCallback& callback,
226 const ProgressCallback& progress_callback) OVERRIDE {
227 NOTREACHED();
231 // Mock DriveService that returns a failure at ResumeUpload().
232 class MockDriveServiceNoConnectionAtResume : public DummyDriveService {
233 // Succeeds and returns an upload location URL.
234 virtual void InitiateUploadNewFile(
235 const base::FilePath& drive_file_path,
236 const std::string& content_type,
237 int64 content_length,
238 const std::string& parent_resource_id,
239 const std::string& title,
240 const InitiateUploadCallback& callback) OVERRIDE {
241 MessageLoop::current()->PostTask(FROM_HERE,
242 base::Bind(callback, HTTP_SUCCESS, GURL(kTestUploadURL)));
245 virtual void InitiateUploadExistingFile(
246 const base::FilePath& drive_file_path,
247 const std::string& content_type,
248 int64 content_length,
249 const std::string& resource_id,
250 const std::string& etag,
251 const InitiateUploadCallback& callback) OVERRIDE {
252 MessageLoop::current()->PostTask(FROM_HERE,
253 base::Bind(callback, HTTP_SUCCESS, GURL(kTestUploadURL)));
256 // Returns error.
257 virtual void ResumeUpload(
258 UploadMode upload_mode,
259 const base::FilePath& drive_file_path,
260 const GURL& upload_url,
261 int64 start_position,
262 int64 end_position,
263 int64 content_length,
264 const std::string& content_type,
265 const scoped_refptr<net::IOBuffer>& buf,
266 const UploadRangeCallback& callback,
267 const ProgressCallback& progress_callback) OVERRIDE {
268 MessageLoop::current()->PostTask(FROM_HERE,
269 base::Bind(callback,
270 UploadRangeResponse(GDATA_NO_CONNECTION, -1, -1),
271 base::Passed(scoped_ptr<ResourceEntry>())));
275 class DriveUploaderTest : public testing::Test {
276 public:
277 DriveUploaderTest()
278 : ui_thread_(content::BrowserThread::UI, &message_loop_) {
281 virtual void SetUp() OVERRIDE {
282 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
285 virtual void TearDown() OVERRIDE {
286 ASSERT_TRUE(temp_dir_.Delete());
289 protected:
290 MessageLoopForUI message_loop_;
291 content::TestBrowserThread ui_thread_;
292 base::ScopedTempDir temp_dir_;
295 } // namespace
297 TEST_F(DriveUploaderTest, UploadExisting0KB) {
298 base::FilePath local_path;
299 std::string data;
300 ASSERT_TRUE(CreateFileOfSpecifiedSize(temp_dir_.path(), 0,
301 &local_path, &data));
303 DriveUploadError error = DRIVE_UPLOAD_ERROR_ABORT;
304 base::FilePath drive_path;
305 base::FilePath file_path;
306 scoped_ptr<ResourceEntry> resource_entry;
308 MockDriveServiceWithUploadExpectation mock_service(data);
309 DriveUploader uploader(&mock_service);
310 std::vector<test_util::ProgressInfo> upload_progress_values;
311 uploader.UploadExistingFile(
312 kTestInitiateUploadResourceId,
313 base::FilePath::FromUTF8Unsafe(kTestDrivePath),
314 local_path,
315 kTestMimeType,
316 std::string(), // etag
317 test_util::CreateCopyResultCallback(
318 &error, &drive_path, &file_path, &resource_entry),
319 base::Bind(&test_util::AppendProgressCallbackResult,
320 &upload_progress_values));
321 test_util::RunBlockingPoolTask();
323 EXPECT_EQ(1, mock_service.resume_upload_call_count());
324 EXPECT_EQ(0, mock_service.received_bytes());
325 EXPECT_EQ(DRIVE_UPLOAD_OK, error);
326 EXPECT_EQ(base::FilePath::FromUTF8Unsafe(kTestDrivePath), drive_path);
327 EXPECT_EQ(local_path, file_path);
328 ASSERT_TRUE(resource_entry);
329 EXPECT_EQ(kTestDummyId, resource_entry->id());
330 ASSERT_EQ(1U, upload_progress_values.size());
331 EXPECT_EQ(test_util::ProgressInfo(0, 0), upload_progress_values[0]);
334 TEST_F(DriveUploaderTest, UploadExisting512KB) {
335 base::FilePath local_path;
336 std::string data;
337 ASSERT_TRUE(CreateFileOfSpecifiedSize(temp_dir_.path(), 512 * 1024,
338 &local_path, &data));
340 DriveUploadError error = DRIVE_UPLOAD_ERROR_ABORT;
341 base::FilePath drive_path;
342 base::FilePath file_path;
343 scoped_ptr<ResourceEntry> resource_entry;
345 MockDriveServiceWithUploadExpectation mock_service(data);
346 DriveUploader uploader(&mock_service);
347 std::vector<test_util::ProgressInfo> upload_progress_values;
348 uploader.UploadExistingFile(
349 kTestInitiateUploadResourceId,
350 base::FilePath::FromUTF8Unsafe(kTestDrivePath),
351 local_path,
352 kTestMimeType,
353 std::string(), // etag
354 test_util::CreateCopyResultCallback(
355 &error, &drive_path, &file_path, &resource_entry),
356 base::Bind(&test_util::AppendProgressCallbackResult,
357 &upload_progress_values));
358 test_util::RunBlockingPoolTask();
360 // 512KB upload should not be split into multiple chunks.
361 EXPECT_EQ(1, mock_service.resume_upload_call_count());
362 EXPECT_EQ(512 * 1024, mock_service.received_bytes());
363 EXPECT_EQ(DRIVE_UPLOAD_OK, error);
364 EXPECT_EQ(base::FilePath::FromUTF8Unsafe(kTestDrivePath), drive_path);
365 EXPECT_EQ(local_path, file_path);
366 ASSERT_TRUE(resource_entry);
367 EXPECT_EQ(kTestDummyId, resource_entry->id());
368 ASSERT_EQ(1U, upload_progress_values.size());
369 EXPECT_EQ(test_util::ProgressInfo(512 * 1024, 512 * 1024),
370 upload_progress_values[0]);
373 TEST_F(DriveUploaderTest, UploadExisting1234KB) {
374 base::FilePath local_path;
375 std::string data;
376 ASSERT_TRUE(CreateFileOfSpecifiedSize(temp_dir_.path(), 1234 * 1024,
377 &local_path, &data));
379 DriveUploadError error = DRIVE_UPLOAD_ERROR_ABORT;
380 base::FilePath drive_path;
381 base::FilePath file_path;
382 scoped_ptr<ResourceEntry> resource_entry;
384 MockDriveServiceWithUploadExpectation mock_service(data);
385 DriveUploader uploader(&mock_service);
386 std::vector<test_util::ProgressInfo> upload_progress_values;
387 uploader.UploadExistingFile(
388 kTestInitiateUploadResourceId,
389 base::FilePath::FromUTF8Unsafe(kTestDrivePath),
390 local_path,
391 kTestMimeType,
392 std::string(), // etag
393 test_util::CreateCopyResultCallback(
394 &error, &drive_path, &file_path, &resource_entry),
395 base::Bind(&test_util::AppendProgressCallbackResult,
396 &upload_progress_values));
397 test_util::RunBlockingPoolTask();
399 // The file should be split into 3 chunks (1234 = 512 + 512 + 210).
400 EXPECT_EQ(3, mock_service.resume_upload_call_count());
401 EXPECT_EQ(1234 * 1024, mock_service.received_bytes());
402 EXPECT_EQ(DRIVE_UPLOAD_OK, error);
403 EXPECT_EQ(base::FilePath::FromUTF8Unsafe(kTestDrivePath), drive_path);
404 EXPECT_EQ(local_path, file_path);
405 ASSERT_TRUE(resource_entry);
406 EXPECT_EQ(kTestDummyId, resource_entry->id());
407 // It is the duty of DriveUploader to accumulate up the progress value.
408 ASSERT_EQ(3U, upload_progress_values.size());
409 EXPECT_EQ(test_util::ProgressInfo(512 * 1024, 1234 * 1024),
410 upload_progress_values[0]);
411 EXPECT_EQ(test_util::ProgressInfo(1024 * 1024, 1234 * 1024),
412 upload_progress_values[1]);
413 EXPECT_EQ(test_util::ProgressInfo(1234 * 1024, 1234 * 1024),
414 upload_progress_values[2]);
417 TEST_F(DriveUploaderTest, UploadNew1234KB) {
418 base::FilePath local_path;
419 std::string data;
420 ASSERT_TRUE(CreateFileOfSpecifiedSize(temp_dir_.path(), 1234 * 1024,
421 &local_path, &data));
423 DriveUploadError error = DRIVE_UPLOAD_ERROR_ABORT;
424 base::FilePath drive_path;
425 base::FilePath file_path;
426 scoped_ptr<ResourceEntry> resource_entry;
428 MockDriveServiceWithUploadExpectation mock_service(data);
429 DriveUploader uploader(&mock_service);
430 uploader.UploadNewFile(
431 kTestInitiateUploadParentResourceId,
432 base::FilePath::FromUTF8Unsafe(kTestDrivePath),
433 local_path,
434 kTestDocumentTitle,
435 kTestMimeType,
436 test_util::CreateCopyResultCallback(
437 &error, &drive_path, &file_path, &resource_entry),
438 google_apis::ProgressCallback());
439 test_util::RunBlockingPoolTask();
441 // The file should be split into 3 chunks (1234 = 512 + 512 + 210).
442 EXPECT_EQ(3, mock_service.resume_upload_call_count());
443 EXPECT_EQ(1234 * 1024, mock_service.received_bytes());
444 EXPECT_EQ(DRIVE_UPLOAD_OK, error);
445 EXPECT_EQ(base::FilePath::FromUTF8Unsafe(kTestDrivePath), drive_path);
446 EXPECT_EQ(local_path, file_path);
447 ASSERT_TRUE(resource_entry);
448 EXPECT_EQ(kTestDummyId, resource_entry->id());
451 TEST_F(DriveUploaderTest, InitiateUploadFail) {
452 base::FilePath local_path;
453 std::string data;
454 ASSERT_TRUE(CreateFileOfSpecifiedSize(temp_dir_.path(), 512 * 1024,
455 &local_path, &data));
457 DriveUploadError error = DRIVE_UPLOAD_OK;
458 base::FilePath drive_path;
459 base::FilePath file_path;
460 scoped_ptr<ResourceEntry> resource_entry;
462 MockDriveServiceNoConnectionAtInitiate mock_service;
463 DriveUploader uploader(&mock_service);
464 uploader.UploadExistingFile(
465 kTestInitiateUploadResourceId,
466 base::FilePath::FromUTF8Unsafe(kTestDrivePath),
467 local_path,
468 kTestMimeType,
469 std::string(), // etag
470 test_util::CreateCopyResultCallback(
471 &error, &drive_path, &file_path, &resource_entry),
472 google_apis::ProgressCallback());
473 test_util::RunBlockingPoolTask();
475 EXPECT_EQ(DRIVE_UPLOAD_ERROR_ABORT, error);
478 TEST_F(DriveUploaderTest, InitiateUploadNoConflict) {
479 base::FilePath local_path;
480 std::string data;
481 ASSERT_TRUE(CreateFileOfSpecifiedSize(temp_dir_.path(), 512 * 1024,
482 &local_path, &data));
484 DriveUploadError error = DRIVE_UPLOAD_ERROR_ABORT;
485 base::FilePath drive_path;
486 base::FilePath file_path;
487 scoped_ptr<ResourceEntry> resource_entry;
489 MockDriveServiceWithUploadExpectation mock_service(data);
490 DriveUploader uploader(&mock_service);
491 uploader.UploadExistingFile(
492 kTestInitiateUploadResourceId,
493 base::FilePath::FromUTF8Unsafe(kTestDrivePath),
494 local_path,
495 kTestMimeType,
496 kTestETag,
497 test_util::CreateCopyResultCallback(
498 &error, &drive_path, &file_path, &resource_entry),
499 google_apis::ProgressCallback());
500 test_util::RunBlockingPoolTask();
502 EXPECT_EQ(DRIVE_UPLOAD_OK, error);
505 TEST_F(DriveUploaderTest, InitiateUploadConflict) {
506 base::FilePath local_path;
507 std::string data;
508 ASSERT_TRUE(CreateFileOfSpecifiedSize(temp_dir_.path(), 512 * 1024,
509 &local_path, &data));
510 const std::string kDestinationETag("destination_etag");
512 DriveUploadError error = DRIVE_UPLOAD_ERROR_ABORT;
513 base::FilePath drive_path;
514 base::FilePath file_path;
515 scoped_ptr<ResourceEntry> resource_entry;
517 MockDriveServiceWithUploadExpectation mock_service(data);
518 DriveUploader uploader(&mock_service);
519 uploader.UploadExistingFile(
520 kTestInitiateUploadResourceId,
521 base::FilePath::FromUTF8Unsafe(kTestDrivePath),
522 local_path,
523 kTestMimeType,
524 kDestinationETag,
525 test_util::CreateCopyResultCallback(
526 &error, &drive_path, &file_path, &resource_entry),
527 google_apis::ProgressCallback());
528 test_util::RunBlockingPoolTask();
530 EXPECT_EQ(DRIVE_UPLOAD_ERROR_CONFLICT, error);
533 TEST_F(DriveUploaderTest, ResumeUploadFail) {
534 base::FilePath local_path;
535 std::string data;
536 ASSERT_TRUE(CreateFileOfSpecifiedSize(temp_dir_.path(), 512 * 1024,
537 &local_path, &data));
539 DriveUploadError error = DRIVE_UPLOAD_OK;
540 base::FilePath drive_path;
541 base::FilePath file_path;
542 scoped_ptr<ResourceEntry> resource_entry;
544 MockDriveServiceNoConnectionAtResume mock_service;
545 DriveUploader uploader(&mock_service);
546 uploader.UploadExistingFile(
547 kTestInitiateUploadResourceId,
548 base::FilePath::FromUTF8Unsafe(kTestDrivePath),
549 local_path,
550 kTestMimeType,
551 std::string(), // etag
552 test_util::CreateCopyResultCallback(
553 &error, &drive_path, &file_path, &resource_entry),
554 google_apis::ProgressCallback());
555 test_util::RunBlockingPoolTask();
557 EXPECT_EQ(DRIVE_UPLOAD_ERROR_ABORT, error);
560 TEST_F(DriveUploaderTest, NonExistingSourceFile) {
561 DriveUploadError error = DRIVE_UPLOAD_ERROR_ABORT;
562 base::FilePath drive_path;
563 base::FilePath file_path;
564 scoped_ptr<ResourceEntry> resource_entry;
566 DriveUploader uploader(NULL); // NULL, the service won't be used.
567 uploader.UploadExistingFile(
568 kTestInitiateUploadResourceId,
569 base::FilePath::FromUTF8Unsafe(kTestDrivePath),
570 temp_dir_.path().AppendASCII("_this_path_should_not_exist_"),
571 kTestMimeType,
572 std::string(), // etag
573 test_util::CreateCopyResultCallback(
574 &error, &drive_path, &file_path, &resource_entry),
575 google_apis::ProgressCallback());
576 test_util::RunBlockingPoolTask();
578 // Should return failure without doing any attempt to connect to the server.
579 EXPECT_EQ(DRIVE_UPLOAD_ERROR_NOT_FOUND, error);
582 } // namespace google_apis